Initial community commit
This commit is contained in:
parent
537bcbc862
commit
fc06254474
16440 changed files with 4239995 additions and 2 deletions
15
Src/nde/Android.mk
Normal file
15
Src/nde/Android.mk
Normal file
|
@ -0,0 +1,15 @@
|
|||
LOCAL_PATH:= $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := nde
|
||||
LOCAL_CFLAGS += -D__ANDROID__
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/..
|
||||
# make base stuff
|
||||
LOCAL_SRC_FILES := Crc.cpp Database.cpp DBUtils.cpp Field.cpp Filter.cpp Index.cpp Int64Field.cpp Int128Field.cpp LinkedList.cpp NDEString.cpp
|
||||
# make platform-specific field classes
|
||||
LOCAL_SRC_FILES += android/Binary32Field.cpp android/BinaryField.cpp android/ColumnField.cpp android/FilenameField.cpp android/IndexField.cpp
|
||||
LOCAL_SRC_FILES += android/IntegerField.cpp android/StringField.cpp
|
||||
# make rest of platform-specific classes
|
||||
LOCAL_SRC_FILES += android/IndexRecord.cpp android/nde_c.cpp android/nde_init.cpp android/Query.cpp android/Record.cpp android/Scanner.cpp android/Table.cpp android/Vfs.cpp
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
8
Src/nde/Binary32Field.h
Normal file
8
Src/nde/Binary32Field.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#ifdef __APPLE__
|
||||
#include "osx/Binary32Field.h"
|
||||
#elif defined(_WIN32)
|
||||
#include "win/Binary32Field.h"
|
||||
#elif defined(__ANDROID__)
|
||||
#include "android/Binary32Field.h"
|
||||
#endif
|
8
Src/nde/BinaryField.h
Normal file
8
Src/nde/BinaryField.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#ifdef __APPLE__
|
||||
#include "osx/BinaryField.h"
|
||||
#elif defined(_WIN32)
|
||||
#include "win/BinaryField.h"
|
||||
#elif defined(__ANDROID__)
|
||||
#include "android/BinaryField.h"
|
||||
#endif
|
7
Src/nde/CRC.H
Normal file
7
Src/nde/CRC.H
Normal file
|
@ -0,0 +1,7 @@
|
|||
#ifndef __CRC_H
|
||||
#define __CRC_H
|
||||
|
||||
unsigned long int crc32file(char *name);
|
||||
unsigned long int crc32str(char *name);
|
||||
|
||||
#endif
|
8
Src/nde/ColumnField.h
Normal file
8
Src/nde/ColumnField.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#ifdef __APPLE__
|
||||
#include "osx/ColumnField.h"
|
||||
#elif defined(_WIN32)
|
||||
#include "win/ColumnField.h"
|
||||
#elif defined(__ANDROID__)
|
||||
#include "android/ColumnField.h"
|
||||
#endif
|
88
Src/nde/Crc.cpp
Normal file
88
Src/nde/Crc.cpp
Normal file
|
@ -0,0 +1,88 @@
|
|||
#include "nde.h"
|
||||
#include <stdio.h>
|
||||
|
||||
static unsigned int crc_32_tab[] = {
|
||||
0xD202Ef8dL, 0xA505DF1BL, 0x3C0C8EA1L, 0x4B0BBE37L, 0xD56F2B94L, 0xA2681B02L, 0x3B614AB8L, 0x4C667A2EL,
|
||||
0xDCD967BFL, 0xABDE5729L, 0x32D70693L, 0x45D03605L, 0xDBB4A3A6L, 0xACB39330L, 0x35BAC28AL, 0x42BDF21CL,
|
||||
0xCFB5FFE9L, 0xB8B2CF7FL, 0x21BB9EC5L, 0x56BCAE53L, 0xC8D83BF0L, 0xBFDF0B66L, 0x26D65ADCL, 0x51D16A4AL,
|
||||
0xC16E77DBL, 0xB669474DL, 0x2F6016F7L, 0x58672661L, 0xC603B3C2L, 0xB1048354L, 0x280DD2EEL, 0x5F0AE278L,
|
||||
0xE96CCF45L, 0x9E6BFFD3L, 0x0762AE69L, 0x70659EFFL, 0xEE010B5CL, 0x99063BCAL, 0x000F6A70L, 0x77085AE6L,
|
||||
0xE7B74777L, 0x90B077E1L, 0x09B9265BL, 0x7EBE16CDL, 0xE0DA836EL, 0x97DDB3F8L, 0x0ED4E242L, 0x79D3D2D4L,
|
||||
0xF4DBDF21L, 0x83DCEFB7L, 0x1AD5BE0DL, 0x6DD28E9BL, 0xF3B61B38L, 0x84B12BAEL, 0x1DB87A14L, 0x6ABF4A82L,
|
||||
0xFA005713L, 0x8D076785L, 0x140E363FL, 0x630906A9L, 0xFD6D930AL, 0x8A6AA39CL, 0x1363F226L, 0x6464C2B0L,
|
||||
0xA4DEAE1DL, 0xD3D99E8BL, 0x4AD0CF31L, 0x3DD7FFA7L, 0xA3B36A04L, 0xD4B45A92L, 0x4DBD0B28L, 0x3ABA3BBEL,
|
||||
0xAA05262FL, 0xDD0216B9L, 0x440B4703L, 0x330C7795L, 0xAD68E236L, 0xDA6FD2A0L, 0x4366831AL, 0x3461B38CL,
|
||||
0xB969BE79L, 0xCE6E8EEFL, 0x5767DF55L, 0x2060EFC3L, 0xBE047A60L, 0xC9034AF6L, 0x500A1B4CL, 0x270D2BDAL,
|
||||
0xB7B2364BL, 0xC0B506DDL, 0x59BC5767L, 0x2EBB67F1L, 0xB0DFF252L, 0xC7D8C2C4L, 0x5ED1937EL, 0x29D6A3E8L,
|
||||
0x9FB08ED5L, 0xE8B7BE43L, 0x71BEEFF9L, 0x06B9DF6FL, 0x98DD4ACCL, 0xEFDA7A5AL, 0x76D32BE0L, 0x01D41B76L,
|
||||
0x916B06E7L, 0xE66C3671L, 0x7F6567CBL, 0x0862575DL, 0x9606C2FEL, 0xE101F268L, 0x7808A3D2L, 0x0F0F9344L,
|
||||
0x82079EB1L, 0xF500AE27L, 0x6C09FF9DL, 0x1B0ECF0BL, 0x856A5AA8L, 0xF26D6A3EL, 0x6B643B84L, 0x1C630B12L,
|
||||
0x8CDC1683L, 0xFBDB2615L, 0x62D277AFL, 0x15D54739L, 0x8BB1D29AL, 0xFCB6E20CL, 0x65BFB3B6L, 0x12B88320L,
|
||||
0x3FBA6CADL, 0x48BD5C3BL, 0xD1B40D81L, 0xA6B33D17L, 0x38D7A8B4L, 0x4FD09822L, 0xD6D9C998L, 0xA1DEF90EL,
|
||||
0x3161E49FL, 0x4666D409L, 0xDF6F85B3L, 0xA868B525L, 0x360C2086L, 0x410B1010L, 0xD80241AAL, 0xAF05713CL,
|
||||
0x220D7CC9L, 0x550A4C5FL, 0xCC031DE5L, 0xBB042D73L, 0x2560B8D0L, 0x52678846L, 0xCB6ED9FCL, 0xBC69E96AL,
|
||||
0x2CD6F4FBL, 0x5BD1C46DL, 0xC2D895D7L, 0xB5DFA541L, 0x2BBB30E2L, 0x5CBC0074L, 0xC5B551CEL, 0xB2B26158L,
|
||||
0x04D44C65L, 0x73D37CF3L, 0xEADA2D49L, 0x9DDD1DDFL, 0x03B9887CL, 0x74BEB8EAL, 0xEDB7E950L, 0x9AB0D9C6L,
|
||||
0x0A0FC457L, 0x7D08F4C1L, 0xE401A57BL, 0x930695EDL, 0x0D62004EL, 0x7A6530D8L, 0xE36C6162L, 0x946B51F4L,
|
||||
0x19635C01L, 0x6E646C97L, 0xF76D3D2DL, 0x806A0DBBL, 0x1E0E9818L, 0x6909A88EL, 0xF000F934L, 0x8707C9A2L,
|
||||
0x17B8D433L, 0x60BFE4A5L, 0xF9B6B51FL, 0x8EB18589L, 0x10D5102AL, 0x67D220BCL, 0xFEDB7106L, 0x89DC4190L,
|
||||
0x49662D3DL, 0x3E611DABL, 0xA7684C11L, 0xD06F7C87L, 0x4E0BE924L, 0x390CD9B2L, 0xA0058808L, 0xD702B89EL,
|
||||
0x47BDA50FL, 0x30BA9599L, 0xA9B3C423L, 0xDEB4F4B5L, 0x40D06116L, 0x37D75180L, 0xAEDE003AL, 0xD9D930ACL,
|
||||
0x54D13D59L, 0x23D60DCFL, 0xBADF5C75L, 0xCDD86CE3L, 0x53BCF940L, 0x24BBC9D6L, 0xBDB2986CL, 0xCAB5A8FAL,
|
||||
0x5A0AB56BL, 0x2D0D85FDL, 0xB404D447L, 0xC303E4D1L, 0x5D677172L, 0x2A6041E4L, 0xB369105EL, 0xC46E20C8L,
|
||||
0x72080DF5L, 0x050F3D63L, 0x9C066CD9L, 0xEB015C4FL, 0x7565C9ECL, 0x0262F97AL, 0x9B6BA8C0L, 0xEC6C9856L,
|
||||
0x7CD385C7L, 0x0BD4B551L, 0x92DDE4EBL, 0xE5DAD47DL, 0x7BBE41DEL, 0x0CB97148L, 0x95B020F2L, 0xE2B71064L,
|
||||
0x6FBF1D91L, 0x18B82D07L, 0x81B17CBDL, 0xF6B64C2BL, 0x68D2D988L, 0x1FD5E91EL, 0x86DCB8A4L, 0xF1DB8832L,
|
||||
0x616495A3L, 0x1663A535L, 0x8F6AF48FL, 0xF86DC419L, 0x660951BAL, 0x110E612CL, 0x88073096L, 0xFF000000L
|
||||
};
|
||||
|
||||
#define UPDC32(octet, crc) (crc_32_tab[((crc) ^ (octet)) & 0xff] ^ ((crc) >> 8))
|
||||
|
||||
unsigned long int crc32file(char *name)
|
||||
{
|
||||
register FILE *fin;
|
||||
register unsigned int oldcrc32;
|
||||
register unsigned int crc32;
|
||||
register unsigned int oldcrc;
|
||||
register unsigned char c;
|
||||
|
||||
oldcrc32 = 0;
|
||||
if ((fin=fopen(name, "rb"))==NULL)
|
||||
return 0;
|
||||
while (1) {
|
||||
c=getc(fin);
|
||||
if (feof(fin)) break;
|
||||
oldcrc32 = UPDC32(c, oldcrc32);
|
||||
}
|
||||
|
||||
if (ferror(fin)){
|
||||
fclose(fin);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
crc32 = oldcrc32; oldcrc = oldcrc32 = ~oldcrc32;
|
||||
|
||||
fclose(fin);
|
||||
|
||||
return crc32;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long int crc32str(char *name)
|
||||
{
|
||||
register unsigned int oldcrc32;
|
||||
register unsigned int crc32;
|
||||
register unsigned char c;
|
||||
register int a=0;
|
||||
|
||||
oldcrc32 = 0;
|
||||
while (name[a] != 0) {
|
||||
c=name[a];
|
||||
oldcrc32 = UPDC32(c, oldcrc32);
|
||||
a++;
|
||||
}
|
||||
|
||||
crc32 = oldcrc32; oldcrc32 = oldcrc32;
|
||||
|
||||
return crc32;
|
||||
}
|
573
Src/nde/DBUtils.cpp
Normal file
573
Src/nde/DBUtils.cpp
Normal file
|
@ -0,0 +1,573 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
All Purposes Functions
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "nde.h"
|
||||
#include "BinaryField.h"
|
||||
#include "Binary32Field.h"
|
||||
#include "vfs.h"
|
||||
#include "ColumnField.h"
|
||||
#include "IndexField.h"
|
||||
#include "StringField.h"
|
||||
#include "FilenameField.h"
|
||||
#include "IntegerField.h"
|
||||
#include "Int64Field.h"
|
||||
#include "Int128Field.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
int (WINAPI *findNLSString)(LCID Locale, DWORD dwFindNLSStringFlags, LPCWSTR lpStringSource, int cchSource, LPCWSTR lpStringValue, int cchValue, LPINT pcchFound) = NDE_FindNLSString;
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
bool CompatibleFields(unsigned char oldType, unsigned char newType)
|
||||
{
|
||||
if (oldType == newType) // duh :)
|
||||
return true;
|
||||
// going from an int field to another int equivalent field is OK
|
||||
if ((oldType == FIELD_INTEGER || oldType == FIELD_BOOLEAN || oldType == FIELD_DATETIME || oldType == FIELD_LENGTH || oldType == FIELD_INT64) &&
|
||||
(newType == FIELD_INTEGER || newType == FIELD_BOOLEAN || newType == FIELD_DATETIME || newType == FIELD_LENGTH || newType == FIELD_INT64)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// going from string to filename or filename to string is OK
|
||||
if ((oldType == FIELD_FILENAME && newType == FIELD_STRING)
|
||||
|| (oldType == FIELD_STRING && newType == FIELD_FILENAME))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
uint32_t AllocNewPos(VFILE *Handle)
|
||||
{
|
||||
Vfseek(Handle, 0, SEEK_END);
|
||||
return Vftell(Handle);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Field *TranslateObject(unsigned char Type, Table *tbl)
|
||||
{
|
||||
switch (Type)
|
||||
{
|
||||
case FIELD_COLUMN: //0
|
||||
return new ColumnField();
|
||||
case FIELD_INDEX: //1
|
||||
return new IndexField();
|
||||
case FIELD_STRING: // 3
|
||||
return new StringField();
|
||||
case FIELD_INTEGER: // 4
|
||||
return new IntegerField();
|
||||
case FIELD_BINARY: // 6
|
||||
return new BinaryField();
|
||||
case FIELD_DATETIME: // 10
|
||||
return new DateTimeField();
|
||||
case FIELD_LENGTH: // 11
|
||||
return new LengthField();
|
||||
case FIELD_FILENAME: // 12
|
||||
return new FilenameField();
|
||||
case FIELD_INT64: // 13
|
||||
return new Int64Field();
|
||||
case FIELD_BINARY32: // 14
|
||||
return new Binary32Field();
|
||||
case FIELD_INT128: // 15
|
||||
return new Int128Field();
|
||||
default:
|
||||
#ifdef WIN32
|
||||
if (!tbl->HasErrors())
|
||||
{
|
||||
//MessageBox(plugin.hwndParent, "Your database has been corrupted!\n\nWinamp will try to continue, but some of the library metadata may be lost :(", "Database Error", 0);
|
||||
}
|
||||
#else
|
||||
printf("NDE Error: unknown field type encountered\n");
|
||||
#endif
|
||||
tbl->IncErrorCount();
|
||||
return new Field();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
#ifndef __ANDROID__
|
||||
const void *memmem(const void *a, const void *b, size_t s, size_t l)
|
||||
{
|
||||
size_t n = s - l;
|
||||
while (n--)
|
||||
{
|
||||
if (!memcmp(a, b, l))
|
||||
return a;
|
||||
a = (const uint8_t *)a + 1;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// a faster way of doing min(wcslen(str), _len)
|
||||
static size_t nde_wcsnlen(const wchar_t *str, size_t _len)
|
||||
{
|
||||
size_t len = 0;
|
||||
while (str && *str++)
|
||||
{
|
||||
if (_len == len)
|
||||
return len;
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
// len must be <= wcslen(b)
|
||||
static int nde_wcsnicmp(const wchar_t *a, const wchar_t *b, size_t len)
|
||||
{
|
||||
return CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, a, (int)nde_wcsnlen(a, len), b, (int)len) - 2;
|
||||
}
|
||||
|
||||
/* this is a VERY LIMITED emulation of the vista only function. it ONLY supports the ways we're currently call it. it's also slow. */
|
||||
int WINAPI NDE_FindNLSString(LCID Locale, DWORD dwFindNLSStringFlags, LPCWSTR lpStringSource, int cchSource, LPCWSTR lpStringValue, int cchValue, LPINT pcchFound)
|
||||
{
|
||||
dwFindNLSStringFlags &= ~NORM_LINGUISTIC_CASING; // remove on XP and below, not supported
|
||||
if (dwFindNLSStringFlags & FIND_STARTSWITH)
|
||||
{
|
||||
dwFindNLSStringFlags &= ~FIND_STARTSWITH; // clear flag
|
||||
size_t len = wcslen(lpStringValue);
|
||||
if (CompareStringW(Locale, dwFindNLSStringFlags, lpStringSource, (int)nde_wcsnlen(lpStringSource, len), lpStringValue, (int)len) == CSTR_EQUAL)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else if (dwFindNLSStringFlags & FIND_ENDSWITH)
|
||||
{
|
||||
dwFindNLSStringFlags &= ~FIND_ENDSWITH; // clear flag
|
||||
int lenp = (int)wcslen(lpStringValue), lend = (int)wcslen(lpStringSource);
|
||||
if (lend < lenp) return -1; // too short
|
||||
if (CompareStringW(Locale, dwFindNLSStringFlags, lpStringSource+lend-lenp, -1, lpStringValue, -1) == CSTR_EQUAL)
|
||||
return 0;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
else if (dwFindNLSStringFlags & FIND_FROMSTART)
|
||||
{
|
||||
dwFindNLSStringFlags &= ~FIND_FROMSTART; // clear flag
|
||||
int s2len = (int)wcslen(lpStringValue);
|
||||
int s1len = (int)wcslen(lpStringSource);
|
||||
const wchar_t *p;
|
||||
for (p = lpStringSource;*p && s1len >= s2len;p++,s1len--)
|
||||
if (CompareStringW(Locale, dwFindNLSStringFlags, p, min(s1len, s2len), lpStringValue, (int)s2len) == CSTR_EQUAL)
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int nde_wcsicmp(const wchar_t *a, const wchar_t *b)
|
||||
{
|
||||
return CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE|NORM_IGNORENONSPACE, a, -1, b, -1) - 2;
|
||||
}
|
||||
|
||||
bool nde_wcsbegins(const wchar_t *a, const wchar_t *b)
|
||||
{
|
||||
int index = findNLSString(LOCALE_USER_DEFAULT, FIND_STARTSWITH|NORM_LINGUISTIC_CASING|NORM_IGNORECASE|NORM_IGNORENONSPACE, a, -1, b, -1, 0);
|
||||
return (index != -1);
|
||||
}
|
||||
|
||||
bool nde_wcsends(const wchar_t *a, const wchar_t *b)
|
||||
{
|
||||
int index = findNLSString(LOCALE_USER_DEFAULT, FIND_ENDSWITH|NORM_LINGUISTIC_CASING|NORM_IGNORECASE|NORM_IGNORENONSPACE, a, -1, b, -1, 0);
|
||||
return (index != -1);
|
||||
}
|
||||
|
||||
bool nde_wcscontains(const wchar_t *a, const wchar_t *b)
|
||||
{
|
||||
int index = findNLSString(LOCALE_USER_DEFAULT, FIND_FROMSTART|NORM_LINGUISTIC_CASING|NORM_IGNORECASE|NORM_IGNORENONSPACE, a, -1, b, -1, 0);
|
||||
return index != -1;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
int mywcsicmp(const wchar_t *a, const wchar_t *b)
|
||||
{
|
||||
if (!a && !b) return 0;
|
||||
if (!a && b) return 1;
|
||||
if (!b) return -1;
|
||||
int r = nde_wcsicmp(a, b);
|
||||
return min(max(r, -1), 1);
|
||||
}
|
||||
|
||||
int mywcsicmp_fn(const wchar_t *a, const wchar_t *b)
|
||||
{
|
||||
if (!a && !b) return 0;
|
||||
if (!a && b) return 1;
|
||||
if (!b) return -1;
|
||||
int r = nde_wcsicmp_fn(a, b);
|
||||
return min(max(r, -1), 1);
|
||||
}
|
||||
|
||||
int nde_wcsicmp_fn(const wchar_t *a, const wchar_t *b)
|
||||
{
|
||||
return CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE, a, -1, b, -1) - 2;
|
||||
}
|
||||
|
||||
bool nde_fnbegins(const wchar_t *a, const wchar_t *b)
|
||||
{
|
||||
int index = findNLSString(LOCALE_USER_DEFAULT, FIND_STARTSWITH|NORM_IGNORECASE, a, -1, b, -1, 0);
|
||||
return (index != -1);
|
||||
}
|
||||
|
||||
bool nde_fnends(const wchar_t *a, const wchar_t *b)
|
||||
{
|
||||
int index = findNLSString(LOCALE_USER_DEFAULT, FIND_ENDSWITH|NORM_IGNORECASE, a, -1, b, -1, 0);
|
||||
return (index != -1);
|
||||
}
|
||||
|
||||
bool nde_fncontains(const wchar_t *a, const wchar_t *b)
|
||||
{
|
||||
int index = findNLSString(LOCALE_USER_DEFAULT, FIND_FROMSTART|NORM_IGNORECASE, a, -1, b, -1, 0);
|
||||
return index != -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// a faster way of doing min(wcslen(str), _len)
|
||||
size_t nde_strnlen(const char *str, size_t _len)
|
||||
{
|
||||
size_t len = 0;
|
||||
while (str && *str++)
|
||||
{
|
||||
if (_len == len)
|
||||
return len;
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
// len must be <= strlen(b)
|
||||
int nde_strnicmp(const char *a, const char *b, size_t len)
|
||||
{
|
||||
return strncasecmp(a,b,len);
|
||||
}
|
||||
|
||||
int nde_strnicmp_ignore(const char *a, const char *b, size_t len)
|
||||
{
|
||||
return strncasecmp(a,b,len);
|
||||
}
|
||||
|
||||
char *stristr(const char *s1, const char *s2)
|
||||
{
|
||||
size_t s2len = strlen(s2);
|
||||
const char *p;
|
||||
for (p = s1;*p;p++)
|
||||
if (!nde_strnicmp(p, s2, s2len))
|
||||
return (char *)p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *stristr_ignore(const char *s1, const char *s2)
|
||||
{
|
||||
size_t s2len = strlen(s2);
|
||||
const char *p;
|
||||
for (p = s1;*p;p++)
|
||||
if (!nde_strnicmp_ignore(p, s2, s2len))
|
||||
return (char *)p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
int nde_stricmp(const char *a, const char *b)
|
||||
{
|
||||
return strcasecmp(a,b);
|
||||
}
|
||||
|
||||
int nde_stricmp_ignore(const char *a, const char *b)
|
||||
{
|
||||
return strcasecmp(a,b); // TODO: maybe strcoll?
|
||||
}
|
||||
|
||||
int mystricmp(const char *a, const char *b)
|
||||
{
|
||||
if (!a && !b) return 0;
|
||||
if (!a && b) return 1;
|
||||
if (!b) return -1;
|
||||
int r = nde_stricmp(a, b);
|
||||
return min(max(r, -1), 1);
|
||||
}
|
||||
|
||||
char* mystristr(const char *a, const char *b)
|
||||
{
|
||||
return (!a || !b) ? NULL : stristr(a, b);
|
||||
}
|
||||
|
||||
char* mystristr_fn(const char *a, const char *b)
|
||||
{
|
||||
return (!a || !b) ? NULL : stristr_fn(a, b);
|
||||
}
|
||||
|
||||
int mystricmp_fn(const char *a, const char *b)
|
||||
{
|
||||
if (!a && !b) return 0;
|
||||
if (!a && b) return 1;
|
||||
if (!b) return -1;
|
||||
int r = nde_stricmp_fn(a, b);
|
||||
return min(max(r, -1), 1);
|
||||
}
|
||||
|
||||
char *stristr_fn(const char *s1, const char *s2)
|
||||
{
|
||||
size_t s2len = strlen(s2);
|
||||
const char *p;
|
||||
for (p = s1;*p;p++)
|
||||
if (!nde_strnicmp_fn(p, s2, s2len))
|
||||
return (char *)p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int nde_stricmp_fn(const char *a, const char *b)
|
||||
{
|
||||
return strcasecmp(a,b);
|
||||
}
|
||||
|
||||
int nde_strnicmp_fn(const char *a, const char *b, size_t len)
|
||||
{
|
||||
return strncasecmp(a,b, len);
|
||||
|
||||
}
|
||||
|
||||
static uint16_t swap_utf16LE(uint16_t value)
|
||||
{
|
||||
#ifdef BIG_ENDIAN
|
||||
return (value >> 8) | (value << 8);
|
||||
#else
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint16_t swap_utf16BE(uint16_t value)
|
||||
{
|
||||
#ifdef LITTLE_ENDIAN
|
||||
return (value >> 8) | (value << 8);
|
||||
#else
|
||||
return value;
|
||||
#endif
|
||||
}
|
||||
|
||||
static size_t utf16LE_to_ucs4_character(const uint16_t *utf16_string, size_t len, uint32_t *codepoint)
|
||||
{
|
||||
uint16_t lead = swap_utf16LE(utf16_string[0]);
|
||||
if (lead < 0xD800 || lead >= 0xE000)
|
||||
{
|
||||
return lead;
|
||||
}
|
||||
|
||||
if (lead < 0xDC00)
|
||||
{
|
||||
if (len >= 2)
|
||||
{
|
||||
uint16_t trail = swap_utf16LE(utf16_string[1]);
|
||||
if (trail >= 0xDC00 && trail < 0xE000)
|
||||
{
|
||||
*codepoint = 0x10000 + ((lead - 0xD800) << 10) + (trail - 0xDC00);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*codepoint=0xFFFD; // invalid
|
||||
return 1;
|
||||
}
|
||||
|
||||
static size_t utf16BE_to_ucs4_character(const uint16_t *utf16_string, size_t len, uint32_t *codepoint)
|
||||
{
|
||||
uint16_t lead = swap_utf16LE(utf16_string[0]);
|
||||
if (lead < 0xD800 || lead >= 0xE000)
|
||||
{
|
||||
return lead;
|
||||
}
|
||||
|
||||
if (lead < 0xDC00)
|
||||
{
|
||||
if (len >= 2)
|
||||
{
|
||||
uint16_t trail = swap_utf16LE(utf16_string[1]);
|
||||
if (trail >= 0xDC00 && trail < 0xE000)
|
||||
{
|
||||
*codepoint = 0x10000 + ((lead - 0xD800) << 10) + (trail - 0xDC00);
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*codepoint=0xFFFD; // invalid
|
||||
return 1;
|
||||
}
|
||||
|
||||
static size_t ucs4count(uint32_t codepoint)
|
||||
{
|
||||
if (codepoint < 0x80)
|
||||
return 1;
|
||||
else if (codepoint < 0x800)
|
||||
return 2;
|
||||
else if (codepoint < 0x10000)
|
||||
return 3;
|
||||
else if (codepoint < 0x200000)
|
||||
return 4;
|
||||
else if (codepoint < 0x4000000)
|
||||
return 5;
|
||||
else if (codepoint <= 0x7FFFFFFF)
|
||||
return 6;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t ucs4_to_utf8_character(char *target, uint32_t codepoint, size_t max)
|
||||
{
|
||||
size_t count = ucs4count(codepoint);
|
||||
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
if (count>max) return 0;
|
||||
|
||||
if (target == 0)
|
||||
return count;
|
||||
|
||||
switch (count)
|
||||
{
|
||||
case 6:
|
||||
target[5] = 0x80 | (codepoint & 0x3F);
|
||||
codepoint = codepoint >> 6;
|
||||
codepoint |= 0x4000000;
|
||||
case 5:
|
||||
target[4] = 0x80 | (codepoint & 0x3F);
|
||||
codepoint = codepoint >> 6;
|
||||
codepoint |= 0x200000;
|
||||
case 4:
|
||||
target[3] = 0x80 | (codepoint & 0x3F);
|
||||
codepoint = codepoint >> 6;
|
||||
codepoint |= 0x10000;
|
||||
case 3:
|
||||
target[2] = 0x80 | (codepoint & 0x3F);
|
||||
codepoint = codepoint >> 6;
|
||||
codepoint |= 0x800;
|
||||
case 2:
|
||||
target[1] = 0x80 | (codepoint & 0x3F);
|
||||
codepoint = codepoint >> 6;
|
||||
codepoint |= 0xC0;
|
||||
case 1:
|
||||
target[0] = codepoint;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
size_t utf16LE_to_utf8(const uint16_t *src, size_t source_len, char *dst, size_t out_len)
|
||||
{
|
||||
uint32_t codepoint=0xFFFD;
|
||||
size_t position=0;
|
||||
size_t characters_processed=0;
|
||||
|
||||
if (!dst) // they just want the size
|
||||
{
|
||||
while (source_len)
|
||||
{
|
||||
characters_processed = utf16LE_to_ucs4_character(src, source_len, &codepoint);
|
||||
if (codepoint == 0xFFFD)
|
||||
break;
|
||||
|
||||
if (!codepoint)
|
||||
break;
|
||||
|
||||
source_len -= characters_processed;
|
||||
|
||||
characters_processed = ucs4count(codepoint);
|
||||
if (!characters_processed)
|
||||
break;
|
||||
|
||||
position+=characters_processed;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
while(source_len && position<out_len)
|
||||
{
|
||||
characters_processed = utf16LE_to_ucs4_character(src, source_len, &codepoint);
|
||||
if (codepoint == 0xFFFD)
|
||||
break;
|
||||
|
||||
if (!codepoint)
|
||||
break;
|
||||
|
||||
source_len -= characters_processed;
|
||||
|
||||
characters_processed=ucs4_to_utf8_character(&dst[position], codepoint, out_len-position);
|
||||
if (!characters_processed)
|
||||
break;
|
||||
position+=characters_processed;
|
||||
}
|
||||
if (position<out_len)
|
||||
dst[position]=0;
|
||||
return position;
|
||||
}
|
||||
|
||||
size_t utf16BE_to_utf8(const uint16_t *src, size_t source_len, char *dst, size_t out_len)
|
||||
{
|
||||
uint32_t codepoint=0xFFFD;
|
||||
size_t position=0;
|
||||
size_t characters_processed=0;
|
||||
|
||||
if (!dst) // they just want the size
|
||||
{
|
||||
while (source_len)
|
||||
{
|
||||
characters_processed = utf16BE_to_ucs4_character(src, source_len, &codepoint);
|
||||
if (codepoint == 0xFFFD)
|
||||
break;
|
||||
|
||||
if (!codepoint)
|
||||
break;
|
||||
|
||||
source_len -= characters_processed;
|
||||
|
||||
characters_processed = ucs4count(codepoint);
|
||||
if (!characters_processed)
|
||||
break;
|
||||
|
||||
position+=characters_processed;
|
||||
}
|
||||
return position;
|
||||
}
|
||||
|
||||
while(source_len && position<out_len)
|
||||
{
|
||||
characters_processed = utf16BE_to_ucs4_character(src, source_len, &codepoint);
|
||||
if (codepoint == 0xFFFD)
|
||||
break;
|
||||
|
||||
if (!codepoint)
|
||||
break;
|
||||
|
||||
source_len -= characters_processed;
|
||||
|
||||
characters_processed=ucs4_to_utf8_character(&dst[position], codepoint, out_len-position);
|
||||
if (!characters_processed)
|
||||
break;
|
||||
position+=characters_processed;
|
||||
}
|
||||
if (position<out_len)
|
||||
dst[position]=0;
|
||||
return position;
|
||||
}
|
||||
#endif
|
73
Src/nde/DBUtils.h
Normal file
73
Src/nde/DBUtils.h
Normal file
|
@ -0,0 +1,73 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
All Purposes Functions Prototypes
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __DBUTILS_H
|
||||
#define __DBUTILS_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "vfs.h"
|
||||
#include "field.h"
|
||||
|
||||
bool CompatibleFields(unsigned char oldType, unsigned char newType);
|
||||
uint32_t AllocNewPos(VFILE *Handle);
|
||||
Field *TranslateObject(unsigned char Type, Table *tbl);
|
||||
|
||||
#ifndef __ANDROID__
|
||||
const void *memmem(const void *a, const void *b, size_t s, size_t l);
|
||||
#endif
|
||||
|
||||
#ifdef __ANDROID__
|
||||
char *stristr(const char *s1, const char *s2);
|
||||
int mystricmp(const char *a, const char *b);
|
||||
char* mystristr(const char *a, const char *b);
|
||||
int nde_stricmp(const char *a, const char *b);
|
||||
int nde_stricmp_ignore(const char *a, const char *b); // ignores accents
|
||||
int nde_strnicmp(const char *a, const char *b, size_t len); // len must be <= strlen(b)
|
||||
int nde_strnicmp_ignore(const char *a, const char *b, size_t len); // ignores accents
|
||||
char *stristr_ignore(const char *s1, const char *s2);
|
||||
// filesystem safe versions
|
||||
char* mystristr_fn(const char *a, const char *b);
|
||||
int mystricmp_fn(const char *a, const char *b);
|
||||
char *stristr_fn(const char *s1, const char *s2);
|
||||
extern "C" int NDE_API nde_stricmp_fn(const char *a, const char *b);
|
||||
int nde_strnicmp_fn(const char *a, const char *b, size_t len); // len must be <= strlen(b)
|
||||
|
||||
size_t utf16LE_to_utf8(const uint16_t *src, size_t source_len, char *dst, size_t out_len);
|
||||
size_t utf16BE_to_utf8(const uint16_t *src, size_t source_len, char *dst, size_t out_len);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
int WINAPI NDE_FindNLSString(LCID Locale, DWORD dwFindNLSStringFlags, LPCWSTR lpStringSource, int cchSource, LPCWSTR lpStringValue, int cchValue, LPINT pcchFound);
|
||||
extern int (WINAPI *findNLSString)(LCID Locale, DWORD dwFindNLSStringFlags, LPCWSTR lpStringSource, int cchSource, LPCWSTR lpStringValue, int cchValue, LPINT pcchFound);
|
||||
bool nde_wcsbegins(const wchar_t *a, const wchar_t *b);
|
||||
bool nde_wcsends(const wchar_t *a, const wchar_t *b);
|
||||
bool nde_wcscontains(const wchar_t *a, const wchar_t *b);
|
||||
|
||||
int mywcsicmp(const wchar_t *a, const wchar_t *b);
|
||||
int nde_wcsicmp(const wchar_t *a, const wchar_t *b);
|
||||
|
||||
// filesystem safe versions
|
||||
bool nde_fnbegins(const wchar_t *a, const wchar_t *b);
|
||||
bool nde_fnends(const wchar_t *a, const wchar_t *b);
|
||||
bool nde_fncontains(const wchar_t *a, const wchar_t *b);
|
||||
|
||||
const wchar_t* mywcsistr_fn(const wchar_t *a, const wchar_t *b);
|
||||
int mywcsicmp_fn(const wchar_t *a, const wchar_t *b);
|
||||
extern "C" int NDE_API nde_wcsicmp_fn(const wchar_t *a, const wchar_t *b);
|
||||
#endif
|
||||
|
||||
#ifdef __APPLE__
|
||||
wchar_t *_wcsdup(const wchar_t *val);
|
||||
#endif
|
||||
|
||||
#endif
|
76
Src/nde/Database.cpp
Normal file
76
Src/nde/Database.cpp
Normal file
|
@ -0,0 +1,76 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Database Class
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "Database.h"
|
||||
#include "Table.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Database::Database()
|
||||
{
|
||||
#ifdef WIN32
|
||||
hInstance = (HINSTANCE)0;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
//---------------------------------------------------------------------------
|
||||
Database::Database(HINSTANCE hinst)
|
||||
{
|
||||
hInstance = hinst;
|
||||
}
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Database::~Database()
|
||||
{
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
//---------------------------------------------------------------------------
|
||||
void Database::SetInstance(HINSTANCE inst) {
|
||||
hInstance = inst;
|
||||
}
|
||||
|
||||
HINSTANCE Database::GetInstance() {
|
||||
return hInstance;
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
#ifdef _WIN32
|
||||
Table *Database::OpenTable(const wchar_t *TableName, const wchar_t *IdxName, BOOL Create, BOOL Cached)
|
||||
#else
|
||||
Table *Database::OpenTable(const char *TableName, const char *IdxName, BOOL Create, BOOL Cached)
|
||||
#endif
|
||||
//char *tablefn, char*indexfn, BOOL create)
|
||||
{
|
||||
Table *table = new Table(TableName, IdxName, Create, this, Cached);
|
||||
if (table)
|
||||
{
|
||||
if (table->Open())
|
||||
return table;
|
||||
table->Close();
|
||||
delete table;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Database::CloseTable(Table *table)
|
||||
{
|
||||
if (table)
|
||||
{
|
||||
table->Close();
|
||||
delete table;
|
||||
}
|
||||
}
|
48
Src/nde/Database.h
Normal file
48
Src/nde/Database.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Database Class Prototypes
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __DATABASE_H
|
||||
#define __DATABASE_H
|
||||
|
||||
#include "nde.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
class Database
|
||||
{
|
||||
public:
|
||||
Database();
|
||||
#ifdef WIN32
|
||||
Database(HINSTANCE hinst);
|
||||
HINSTANCE GetInstance();
|
||||
void SetInstance(HINSTANCE hinst);
|
||||
#endif
|
||||
~Database();
|
||||
#ifdef _WIN32
|
||||
Table *OpenTable(const wchar_t *table, const wchar_t *index, BOOL create, BOOL cached);
|
||||
#else
|
||||
Table *OpenTable(const char *table, const char *index, BOOL create, BOOL cached);
|
||||
#endif
|
||||
void CloseTable(Table *table);
|
||||
private:
|
||||
#ifdef WIN32
|
||||
HINSTANCE hInstance;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
281
Src/nde/Field.cpp
Normal file
281
Src/nde/Field.cpp
Normal file
|
@ -0,0 +1,281 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Field Class
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "field.h"
|
||||
#include "vfs.h"
|
||||
#include "table.h"
|
||||
#include "nde.h"
|
||||
#include "dbutils.h"
|
||||
|
||||
#ifdef WIN32
|
||||
#include <malloc.h>
|
||||
#elif defined(__APPLE__)
|
||||
#include <alloca.h>
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void PUT_BINARY(uint8_t *dest, const uint8_t *src, size_t size, size_t pos)
|
||||
{
|
||||
if (src && dest && size > 0)
|
||||
memcpy(dest+pos, src, size);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void GET_BINARY(uint8_t *dest, const uint8_t *src, size_t size, size_t pos)
|
||||
{
|
||||
if (dest && src && size > 0)
|
||||
memcpy(dest, src+pos, size);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void PUT_FLOAT(float f, uint8_t *data, size_t pos)
|
||||
{
|
||||
unsigned int y = *(const unsigned int *)&f;
|
||||
data[pos]=(unsigned char)(y&255); data[pos+1]=(unsigned char)((y>>8)&255); data[pos+2]=(unsigned char)((y>>16)&255); data[pos+3]=(unsigned char)((y>>24)&255);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
float GET_FLOAT(const uint8_t *data, size_t pos)
|
||||
{
|
||||
int a = data[pos]|(data[pos+1]<<8)|(data[pos+2]<<16)|(data[pos+3]<<24);
|
||||
float f = *(const float *)&a;
|
||||
return f;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Field::Field(int FieldPos)
|
||||
{
|
||||
InitField();
|
||||
Pos = FieldPos;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Field::InitField(void)
|
||||
{
|
||||
Type = FIELD_UNKNOWN;
|
||||
Pos = 0;
|
||||
ID = 0;
|
||||
MaxSizeOnDisk = 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Field::Field()
|
||||
{
|
||||
InitField();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Field::~Field()
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Field *Field::ReadField(Table *pTable, int pos, uint32_t *next_position)
|
||||
{
|
||||
return ReadField(pTable, pos, false, next_position);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Field *Field::ReadField(Table *pTable, int pos, bool Quick, uint32_t *next_position)
|
||||
{
|
||||
VFILE *HTable = pTable->Handle;
|
||||
int newPos = pos;
|
||||
int rType = FIELD_REDIRECTOR;
|
||||
unsigned char oType;
|
||||
|
||||
if (!Vflock(HTable, false))
|
||||
return 0;
|
||||
|
||||
while (rType == FIELD_REDIRECTOR)
|
||||
{
|
||||
Vfseek(HTable, Pos, SEEK_SET);
|
||||
if (Vfread(&ID, sizeof(ID), HTable) != 1 ||
|
||||
Vfread(&oType, sizeof(oType), HTable) != 1)
|
||||
{
|
||||
Vfunlock(HTable, false);
|
||||
return NULL;
|
||||
}
|
||||
if (oType == FIELD_REDIRECTOR)
|
||||
{
|
||||
if (Vfread(&newPos, sizeof(newPos), HTable) != 1)
|
||||
{
|
||||
Vfunlock(HTable, false);
|
||||
return NULL;
|
||||
}
|
||||
Pos = newPos;
|
||||
}
|
||||
rType = oType;
|
||||
}
|
||||
if (Quick)
|
||||
Vfseek(HTable, sizeof(MaxSizeOnDisk), SEEK_CUR);
|
||||
else
|
||||
{
|
||||
if (Vfread(&MaxSizeOnDisk, sizeof(MaxSizeOnDisk), HTable) != 1)
|
||||
{
|
||||
Vfunlock(HTable, false);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
uint32_t NextFieldPos = 0;
|
||||
if (Vfread(&NextFieldPos, sizeof(NextFieldPos), HTable) != 1)
|
||||
{
|
||||
Vfunlock(HTable, false);
|
||||
return NULL;
|
||||
}
|
||||
if (next_position) *next_position = NextFieldPos;
|
||||
if (Quick)
|
||||
{
|
||||
Vfunlock(HTable, false);
|
||||
return this;
|
||||
}
|
||||
|
||||
uint32_t PreviousFieldPos = 0;
|
||||
if (Vfread(&PreviousFieldPos, sizeof(PreviousFieldPos), HTable) != 1)
|
||||
{
|
||||
Vfunlock(HTable, false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
Field *O=NULL;
|
||||
O = TranslateObject(oType, pTable);
|
||||
if (O)
|
||||
{
|
||||
O->ID = ID;
|
||||
O->Type = oType;
|
||||
O->Pos = Pos;
|
||||
O->MaxSizeOnDisk = MaxSizeOnDisk;
|
||||
uint8_t *data = NULL;
|
||||
if (HTable->cached && MaxSizeOnDisk > VFILE_INC)
|
||||
{
|
||||
pTable->IncErrorCount();
|
||||
MaxSizeOnDisk = (uint32_t)GetDataSize();
|
||||
O->MaxSizeOnDisk = MaxSizeOnDisk;
|
||||
}
|
||||
else if (HTable->cached)
|
||||
{
|
||||
data = HTable->data+HTable->ptr; // benski> uber-hack
|
||||
Vfseek(HTable, MaxSizeOnDisk, SEEK_CUR);
|
||||
}
|
||||
else
|
||||
{
|
||||
data = (uint8_t *)_malloca(MaxSizeOnDisk);
|
||||
Vfread(data, MaxSizeOnDisk, HTable);
|
||||
}
|
||||
|
||||
if (data)
|
||||
{
|
||||
O->ReadTypedData(data, MaxSizeOnDisk);
|
||||
if (!HTable->cached)
|
||||
{
|
||||
_freea(data);
|
||||
}
|
||||
}
|
||||
Vfunlock(HTable, false);
|
||||
return O;
|
||||
}
|
||||
Vfunlock(HTable, false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Field::WriteField(Table *pTable, Field *previous_field, Field *next_field)
|
||||
{
|
||||
VFILE *HTable = pTable->Handle;
|
||||
if (Pos == -1) return;
|
||||
size_t data_size = GetDataSize();
|
||||
if (HTable->cached && MaxSizeOnDisk > VFILE_INC) {
|
||||
pTable->IncErrorCount();
|
||||
MaxSizeOnDisk = (uint32_t)data_size;
|
||||
}
|
||||
|
||||
if (Pos == 0 || (uint32_t)data_size > MaxSizeOnDisk)
|
||||
{
|
||||
MaxSizeOnDisk = (uint32_t)data_size;
|
||||
uint32_t newPos = AllocNewPos(HTable);
|
||||
if (Pos != 0)
|
||||
{
|
||||
unsigned char v = 0;
|
||||
Vfseek(HTable, Pos, SEEK_SET);
|
||||
Vfwrite(&v, sizeof(v), HTable);
|
||||
v = FIELD_REDIRECTOR;
|
||||
Vfwrite(&v, sizeof(v), HTable);
|
||||
Vfwrite(&newPos, sizeof(newPos), HTable);
|
||||
}
|
||||
Pos = newPos;
|
||||
if (previous_field)
|
||||
{
|
||||
//previous_field->NextFieldPos = Pos;
|
||||
if (previous_field->Pos)
|
||||
{
|
||||
Vfseek(HTable, previous_field->Pos+sizeof(ID)+sizeof(MaxSizeOnDisk)+sizeof(Type), SEEK_SET);
|
||||
Vfwrite(&Pos, sizeof(Pos), HTable);
|
||||
}
|
||||
}
|
||||
if (next_field)
|
||||
{
|
||||
if (next_field->Pos)
|
||||
{
|
||||
Vfseek(HTable, next_field->Pos+sizeof(ID)+sizeof(uint32_t/*NextFieldPos*/)+sizeof(Type)+sizeof(MaxSizeOnDisk), SEEK_SET);
|
||||
Vfwrite(&Pos, sizeof(Pos), HTable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t PreviousFieldPos = 0, NextFieldPos = 0;
|
||||
if (previous_field) PreviousFieldPos = previous_field->GetFieldPos(); else PreviousFieldPos = NULL;
|
||||
if (next_field) NextFieldPos = next_field->GetFieldPos(); else NextFieldPos = NULL;
|
||||
|
||||
Vfseek(HTable, Pos, SEEK_SET);
|
||||
Vfwrite(&ID, sizeof(ID), HTable);
|
||||
Vfwrite(&Type, sizeof(Type), HTable);
|
||||
Vfwrite(&MaxSizeOnDisk, sizeof(MaxSizeOnDisk), HTable);
|
||||
Vfwrite(&NextFieldPos, sizeof(NextFieldPos), HTable);
|
||||
Vfwrite(&PreviousFieldPos, sizeof(PreviousFieldPos), HTable);
|
||||
uint8_t *data = (unsigned char*)_malloca(MaxSizeOnDisk);
|
||||
WriteTypedData(data, MaxSizeOnDisk);
|
||||
Vfwrite(data, MaxSizeOnDisk, HTable);
|
||||
_freea(data);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
uint32_t Field::GetFieldPos(void)
|
||||
{
|
||||
return Pos;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Field *Field::Clone(Table *pTable)
|
||||
{
|
||||
Field *clone = TranslateObject(Type, pTable);
|
||||
size_t size = GetDataSize();
|
||||
uint8_t *data = (unsigned char*)_malloca(size);
|
||||
WriteTypedData(data, size);
|
||||
clone->ReadTypedData(data, size);
|
||||
if (data) _freea(data);
|
||||
clone->Type = Type;
|
||||
//clone->HTable = HTable;
|
||||
clone->Pos = FIELD_CLONE;
|
||||
clone->ID = ID;
|
||||
//clone->NextFieldPos = 0;
|
||||
clone->MaxSizeOnDisk=(uint32_t)size;
|
||||
return clone;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Field::GetType() {
|
||||
return Type;
|
||||
}
|
||||
|
||||
size_t Field::GetTotalSize()
|
||||
{
|
||||
return GetDataSize() + sizeof(ID)+sizeof(Type)+sizeof(MaxSizeOnDisk)+sizeof(uint32_t/*NextFieldPos*/)+sizeof(uint32_t /*PreviousFieldPos*/);
|
||||
}
|
110
Src/nde/Field.h
Normal file
110
Src/nde/Field.h
Normal file
|
@ -0,0 +1,110 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Field Class Prototypes
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __FIELD_H
|
||||
#define __FIELD_H
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <foundation/types.h> // TODO
|
||||
#else
|
||||
#include <bfc/platform/types.h>
|
||||
#endif
|
||||
|
||||
class Table;
|
||||
#include <stdio.h>
|
||||
|
||||
#define PUT_INT(y) data[pos]=(uint8_t)(y&255); data[pos+1]=(uint8_t)((y>>8)&255); data[pos+2]=(uint8_t)((y>>16)&255); data[pos+3]=(uint8_t)((y>>24)&255)
|
||||
#define GET_INT() (int)(data[pos]|(data[pos+1]<<8)|(data[pos+2]<<16)|(data[pos+3]<<24))
|
||||
#define PUT_SHORT(y) data[pos]=(uint8_t)(y&255); data[pos+1]=(uint8_t)((y>>8)&255);
|
||||
#define GET_SHORT() (uint16_t)(data[pos]|(data[pos+1]<<8))
|
||||
#define PUT_PINT(y) data[*pos]=(uint8_t)(y&255); data[*pos+1]=(uint8_t)((y>>8)&255); data[*pos+2]=(uint8_t)((y>>16)&255); data[*pos+3]=(uint8_t)((y>>24)&255)
|
||||
extern float GET_FLOAT(const uint8_t *data, size_t pos);
|
||||
extern void PUT_FLOAT(float f, uint8_t *data, size_t pos);
|
||||
extern void PUT_BINARY(uint8_t *dest, const uint8_t *src, size_t size, size_t pos);
|
||||
extern void GET_BINARY(uint8_t *dest, const uint8_t *src, size_t size, size_t pos);
|
||||
#define PUT_CHAR(y) data[pos]=y
|
||||
#define GET_CHAR() data[pos]
|
||||
#define CHECK_CHAR(l) { if (l < 1) return; l--; }
|
||||
#define CHECK_INT(l) { if (l < 4) return; l-=4; }
|
||||
#define CHECK_INT64(l) { if (l < 8) return; l-=8; }
|
||||
#define CHECK_SHORT(l) { if (l < 2) return; l-=2; }
|
||||
#define CHECK_BIN(l, size) { if (l < size) return; l-=size; }
|
||||
|
||||
#ifdef ASSERT
|
||||
#undef ASSERT
|
||||
#endif
|
||||
#define ASSERT(x) { \
|
||||
if (!(x)) \
|
||||
OutputDebugString("Assertion failed "); \
|
||||
}
|
||||
|
||||
#define _CHECK_CHAR(l) { ASSERT(l >= 1); l-=1; }
|
||||
#define _CHECK_INT(l) { ASSERT(l >= 4); l-=4; }
|
||||
#define _CHECK_SHORT(l) { ASSERT(l >= 2); l-=2; }
|
||||
#define _CHECK_BIN(l, size) { ASSERT(l >= size); l-=size; }
|
||||
|
||||
class Field //: public wa::lists::node_ptr
|
||||
{
|
||||
public:
|
||||
Field();
|
||||
virtual ~Field();
|
||||
virtual Field *Clone(Table *pTable);
|
||||
unsigned char GetFieldId(void)
|
||||
{
|
||||
return ID;
|
||||
}
|
||||
int GetType();
|
||||
size_t GetTotalSize();
|
||||
Field(int FieldPos);
|
||||
Field *ReadField(Table *pTable, int pos, uint32_t *next_position=0);
|
||||
Field *ReadField(Table *pTable, int pos, bool readTyped, uint32_t *next_position=0);
|
||||
void WriteField(Table *pTable, Field *previous_field, Field *next_field);
|
||||
virtual void ReadTypedData(const uint8_t *, size_t /*len*/) { };
|
||||
virtual void WriteTypedData(uint8_t *, size_t) { };
|
||||
virtual size_t GetDataSize(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual int Compare(Field * /*Entry*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual int Starts(Field * /*Entry*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual int Contains(Field * /*Entry*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
virtual bool ApplyFilter(Field * /*Data*/, int /*flags*/)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
uint32_t GetFieldPos(void);
|
||||
void InitField(void);
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t ID;
|
||||
uint8_t Type;
|
||||
};
|
||||
uint32_t _dummy_union_thingy;
|
||||
};
|
||||
protected:
|
||||
uint32_t Pos;
|
||||
|
||||
uint32_t MaxSizeOnDisk;
|
||||
};
|
||||
|
||||
#endif
|
8
Src/nde/FilenameField.h
Normal file
8
Src/nde/FilenameField.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#ifdef __APPLE__
|
||||
#include "osx/FilenameField.h"
|
||||
#elif defined(_WIN32)
|
||||
#include "win/FilenameField.h"
|
||||
#elif defined(__ANDROID__)
|
||||
#include "android/FilenameField.h"
|
||||
#endif
|
69
Src/nde/Filter.cpp
Normal file
69
Src/nde/Filter.cpp
Normal file
|
@ -0,0 +1,69 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Filter Class
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
// Filters can now be a test on a field or a single operator that will pop
|
||||
// one operation from the filters stack. upon AddFilter*, return value will
|
||||
|
||||
#include "Filter.h"
|
||||
#include "Field.h"
|
||||
//---------------------------------------------------------------------------
|
||||
Filter::Filter(unsigned char _Op)
|
||||
{
|
||||
DataField = 0;
|
||||
Op = _Op;
|
||||
Id = -1;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Filter::Filter(Field *Data, unsigned char _Id, unsigned char _Op)
|
||||
{
|
||||
DataField = Data;
|
||||
Op = _Op;
|
||||
Id = _Id;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Filter::~Filter()
|
||||
{
|
||||
delete DataField;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
unsigned char Filter::GetOp(void) const
|
||||
{
|
||||
return Op;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Filter::SetOp(unsigned char _Op)
|
||||
{
|
||||
Op = _Op;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Field *Filter::Data(void) const
|
||||
{
|
||||
return DataField;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Filter::SetData(Field *data)
|
||||
{
|
||||
DataField = data;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Filter::GetId(void) const
|
||||
{
|
||||
return Id;
|
||||
}
|
||||
|
37
Src/nde/Filter.h
Normal file
37
Src/nde/Filter.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Filter Class Prototypes
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __FILTER_H
|
||||
#define __FILTER_H
|
||||
|
||||
#include "LinkedList.h"
|
||||
class Field;
|
||||
class Filter : public LinkedListEntry
|
||||
{
|
||||
private:
|
||||
Field* DataField;
|
||||
unsigned char Op;
|
||||
unsigned char Id;
|
||||
|
||||
public:
|
||||
unsigned char GetOp(void) const;
|
||||
void SetOp(unsigned char Op);
|
||||
Field *Data(void) const;
|
||||
int GetId(void) const;
|
||||
Filter(unsigned char _Op);
|
||||
Filter(Field *Data, unsigned char Id, unsigned char Op);
|
||||
void SetData(Field *data);
|
||||
~Filter() ;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
787
Src/nde/Index.cpp
Normal file
787
Src/nde/Index.cpp
Normal file
|
@ -0,0 +1,787 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Raw Index Class
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "nde.h"
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
const char *iSign="NDEINDEX";
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Index::Index(VFILE *H, unsigned char id, int pos, int type, bool newindex, int nentries, Table *parentTable)
|
||||
{
|
||||
Handle = H;
|
||||
IndexTable = NULL;
|
||||
MaxSize=0;
|
||||
locateUpToDate = false;
|
||||
Id = id;
|
||||
Position = pos;
|
||||
// DataType = type;
|
||||
SecIndex = NULL;
|
||||
InChain=false;
|
||||
InInsert=false;
|
||||
InChainIdx = -1;
|
||||
pTable = parentTable;
|
||||
TableHandle = pTable->Handle;
|
||||
SetGlobalLocateUpToDate(false);
|
||||
|
||||
if (!newindex)
|
||||
{
|
||||
Vfseek(Handle, (int)strlen(__INDEX_SIGNATURE__), SEEK_SET);
|
||||
Vfread(&NEntries, sizeof(NEntries), Handle);
|
||||
}
|
||||
else
|
||||
NEntries = nentries;
|
||||
LoadIndex(newindex);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Index::~Index()
|
||||
{
|
||||
if (IndexTable)
|
||||
free(IndexTable);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Index::Insert(int N)
|
||||
{
|
||||
return Insert(NULL, N, false);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Index::Insert(Index *parindex, int N, bool localonly)
|
||||
{
|
||||
if (InChain) return -1;
|
||||
Index *p = parindex;
|
||||
IndexField *f = 0;
|
||||
locateUpToDate = false;
|
||||
SetGlobalLocateUpToDate(false);
|
||||
InInsert=true;
|
||||
if (N > NEntries) N = NEntries;
|
||||
if ((NEntries+1) > (int)MaxSize)
|
||||
{
|
||||
MaxSize *=2;//+= BLOCK_SIZE;
|
||||
int *newBlock = (int *)calloc(MaxSize, sizeof(int)*2);
|
||||
memcpy(newBlock, IndexTable, NEntries*sizeof(int)*2);
|
||||
free(IndexTable);
|
||||
IndexTable = newBlock;
|
||||
}
|
||||
|
||||
if (N < NEntries && Id == PRIMARY_INDEX)
|
||||
{
|
||||
memmove(IndexTable+(N+1)*2, IndexTable+(N*2), (NEntries-N)*sizeof(int)*2);
|
||||
NEntries++;
|
||||
}
|
||||
else
|
||||
{
|
||||
N=NEntries;
|
||||
NEntries++;
|
||||
}
|
||||
|
||||
Update(N, 0, NULL, localonly);
|
||||
|
||||
// Should be always safe to cat the new record since if we are primary index,
|
||||
// then secondary is sorted, so value will be moved at update
|
||||
// if we are a secondary index, then an insertion will insert at the end of the primary index anyway
|
||||
if (!localonly && SecIndex)
|
||||
{
|
||||
InChain=true;
|
||||
int pp = SecIndex->index->Insert(this, N, false);
|
||||
InChain=false;
|
||||
IndexTable[N*2+1] = pp == -1 ? N : pp;
|
||||
if (N < NEntries-1 && Id == PRIMARY_INDEX)
|
||||
{
|
||||
int pidx = -1;
|
||||
if (!parindex)
|
||||
{
|
||||
int v = pp;
|
||||
f = SecIndex;
|
||||
if (f)
|
||||
{
|
||||
while (f->index->SecIndex->index != this)
|
||||
{
|
||||
v = f->index->GetCooperative(v);
|
||||
f = f->index->SecIndex;
|
||||
}
|
||||
p = f->index;
|
||||
pidx = v;
|
||||
}
|
||||
}
|
||||
if (p && pidx != -1)
|
||||
{
|
||||
p->SetCooperative(pidx, N);
|
||||
UpdateMe(p, N, NEntries);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InInsert=false;
|
||||
return N;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Index::LoadIndex(bool newindex)
|
||||
{
|
||||
if (IndexTable)
|
||||
free(IndexTable);
|
||||
MaxSize = ((NEntries) / BLOCK_SIZE + 1) * BLOCK_SIZE;
|
||||
IndexTable = (int *)calloc(MaxSize, sizeof(int)*2);
|
||||
if (!newindex)
|
||||
{
|
||||
Vfseek(Handle, (int)strlen(__INDEX_SIGNATURE__)+4+((NEntries*4*2)+4)*(Position+1), SEEK_SET);
|
||||
int v = 0;
|
||||
Vfread(&v, sizeof(v), Handle);
|
||||
Id = (unsigned char)v;
|
||||
Vfread(IndexTable, NEntries*2*sizeof(int), Handle);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Index::Update(int Idx, int Pos, RecordBase *record, bool localonly)
|
||||
{
|
||||
return Update(NULL, -1, Idx, Pos, record, false, localonly);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Index::Update(Index *parindex, int paridx, int Idx, int Pos, RecordBase *record, bool forceLast, bool localonly)
|
||||
{
|
||||
if (InChain) return InChainIdx;
|
||||
int NewIdx=Idx;
|
||||
int oldSecPtr = IndexTable[Idx*2+1];
|
||||
if (!forceLast && Id == PRIMARY_INDEX || record == NULL || Idx < NUM_SPECIAL_RECORDS)
|
||||
{
|
||||
if (Idx < NEntries && Idx >= 0)
|
||||
{
|
||||
IndexTable[Idx*2] = Pos;
|
||||
if (!localonly && SecIndex && SecIndex->index != this && !InInsert)
|
||||
{
|
||||
InChain=true;
|
||||
InChainIdx = Idx;
|
||||
SecIndex->index->Update(this, Idx, IndexTable[Idx*2+1], Pos, record, forceLast, false);
|
||||
InChainIdx = -1;
|
||||
InChain=false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef WIN32
|
||||
MessageBox(NULL, L"Updating outside range", L"Oops", 16);
|
||||
#else
|
||||
printf("NDE Error: updating outside range!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (forceLast)
|
||||
NewIdx = NEntries;
|
||||
else
|
||||
{
|
||||
if (Pos != Get(Idx) || Id != PRIMARY_INDEX)
|
||||
{
|
||||
int state = 0;
|
||||
NewIdx = FindSortedPlace(record->GetField(Id), Idx, &state, QFIND_ENTIRE_SCOPE);
|
||||
}
|
||||
}
|
||||
|
||||
if (NewIdx <= NEntries && NewIdx >= NUM_SPECIAL_RECORDS)
|
||||
{
|
||||
if (NewIdx != Idx)
|
||||
{
|
||||
Index *p = parindex;
|
||||
IndexField *f = 0;
|
||||
int pidx = paridx;
|
||||
NewIdx = MoveIndex(Idx, NewIdx);
|
||||
if (SecIndex->index != this)
|
||||
{
|
||||
if (!parindex)
|
||||
{
|
||||
int v = GetCooperative(NewIdx);
|
||||
f = SecIndex;
|
||||
if (f)
|
||||
{
|
||||
while (f->index->SecIndex->index != this)
|
||||
{
|
||||
v = f->index->GetCooperative(v);
|
||||
f = f->index->SecIndex;
|
||||
}
|
||||
p = f->index;
|
||||
pidx = v;
|
||||
}
|
||||
}
|
||||
if (p)
|
||||
{
|
||||
p->SetCooperative(pidx, NewIdx);
|
||||
UpdateMe(p, NewIdx, Idx);
|
||||
}
|
||||
}
|
||||
}
|
||||
IndexTable[NewIdx*2] = Pos;
|
||||
if (!localonly && SecIndex && SecIndex->index != this && !InInsert) // Actually, we should never be InInsert and here, but lets cover our ass
|
||||
{
|
||||
InChain=true;
|
||||
InChainIdx = oldSecPtr;
|
||||
SecIndex->index->Update(this, NewIdx, oldSecPtr, Pos, record, forceLast, false);
|
||||
InChainIdx = -1;
|
||||
InChain=false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef WIN32
|
||||
MessageBox(NULL, L"QSort failed and tried to update index outside range", L"Oops", 16);
|
||||
#else
|
||||
printf("NDE Error: qsort failed and tried to update index outside range!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
locateUpToDate = false;
|
||||
SetGlobalLocateUpToDate(false);
|
||||
pTable->IndexModified();
|
||||
return NewIdx;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Index::Get(int Idx)
|
||||
{
|
||||
if (Idx < NEntries)
|
||||
return IndexTable[Idx*2];
|
||||
else
|
||||
{
|
||||
#ifdef WIN32
|
||||
MessageBox(NULL, L"Requested index outside range", L"Oops", 16);
|
||||
#else
|
||||
printf("NDE Error: requested index outside range!\n");
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Index::Set(int Idx, int P)
|
||||
{
|
||||
if (Idx < NEntries)
|
||||
IndexTable[Idx*2]=P;
|
||||
else
|
||||
{
|
||||
#ifdef WIN32
|
||||
MessageBox(NULL, L"Updating index outside range", L"Oops", 16);
|
||||
#else
|
||||
printf("NDE Error: updating index outside range!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Index::WriteIndex(void)
|
||||
{
|
||||
if (Id == PRIMARY_INDEX)
|
||||
{
|
||||
Vfseek(Handle, (int)strlen(__INDEX_SIGNATURE__), SEEK_SET);
|
||||
Vfwrite(&NEntries, sizeof(NEntries), Handle);
|
||||
}
|
||||
Vfseek(Handle, (int)strlen(__INDEX_SIGNATURE__)+4+((NEntries*4*2)+4)*(Position+1), SEEK_SET);
|
||||
int v=(int)Id;
|
||||
Vfwrite(&v, sizeof(v), Handle);
|
||||
Vfwrite(IndexTable, NEntries*2*sizeof(int), Handle);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Index::MoveIndex(int idx, int newidx)
|
||||
{
|
||||
if (idx == newidx)
|
||||
return newidx;
|
||||
int oldPos=IndexTable[idx*2], oldPtr=IndexTable[idx*2+1];
|
||||
|
||||
if (NEntries > idx+1)
|
||||
memmove(IndexTable+idx*2, IndexTable+(idx+1)*2, (NEntries-idx)*sizeof(int)*2);
|
||||
if (newidx > idx)
|
||||
newidx--;
|
||||
if (NEntries > newidx)
|
||||
memmove(IndexTable+(newidx+1)*2, IndexTable+newidx*2, (NEntries-newidx-1)*sizeof(int)*2);
|
||||
IndexTable[newidx*2] = oldPos;
|
||||
IndexTable[newidx*2+1] = oldPtr;
|
||||
return newidx;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Index::Colaborate(IndexField *secindex)
|
||||
{
|
||||
SecIndex = secindex;
|
||||
for (int i=0;i<NUM_SPECIAL_RECORDS;i++)
|
||||
/*secindex->index->*/SetCooperative(i, i);
|
||||
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Index::Propagate(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!SecIndex || SecIndex->ID == PRIMARY_INDEX) return;
|
||||
SecIndex->index->NEntries=NUM_SPECIAL_RECORDS;
|
||||
for (i=0;i<NUM_SPECIAL_RECORDS;i++)
|
||||
{
|
||||
SecIndex->index->Set(i, Get(i));
|
||||
SecIndex->index->SetCooperative(i, GetCooperative(i));
|
||||
}
|
||||
|
||||
Scanner *s = pTable->NewScanner();
|
||||
if (!s)
|
||||
{
|
||||
#ifdef WIN32
|
||||
MessageBox(NULL, L"Failed to create a scanner in reindex", L"Oops", 16);
|
||||
#else
|
||||
printf("NDE Error: failed to create a scanner in reindex!\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
int *coopSave = (int *)calloc(NEntries, sizeof(int));
|
||||
if (!coopSave)
|
||||
{
|
||||
#ifdef WIN32
|
||||
MessageBox(NULL, L"Alloc failed in reindex", L"Oops", 16);
|
||||
#else
|
||||
printf("NDE Error: alloc failed in reindex!\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
for (i=0;i<NEntries;i++)
|
||||
{
|
||||
coopSave[i] = GetCooperative(i);
|
||||
SetCooperative(i, i);
|
||||
}
|
||||
|
||||
if (SecIndex->index->SecIndex->index->Id != PRIMARY_INDEX)
|
||||
{
|
||||
#ifdef WIN32
|
||||
MessageBox(NULL, L"Propagating existing index", L"Oops", 16);
|
||||
#else
|
||||
printf("NDE Error: propagating existing index!\n");
|
||||
#endif
|
||||
free(coopSave);
|
||||
return;
|
||||
}
|
||||
|
||||
s->SetWorkingIndexById(-1);
|
||||
|
||||
for (i=NUM_SPECIAL_RECORDS;i<NEntries;i++)
|
||||
{
|
||||
Record *rec = s->GetRecord(coopSave[i]);
|
||||
if (rec)
|
||||
{
|
||||
SecIndex->index->NEntries++;
|
||||
// SecIndex->index->Insert(NULL, i, true);
|
||||
SecIndex->index->SetCooperative(i, coopSave[i]);
|
||||
SecIndex->index->Set(i, Get(i));
|
||||
SecIndex->index->Update(i, SecIndex->index->Get(i), rec, true);
|
||||
/* SecIndex->index->SetCooperative(i, q);*/
|
||||
rec->Release();
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef WIN32
|
||||
MessageBox(NULL, L"Unable to read record in reindex", L"Oops", 16);
|
||||
#else
|
||||
printf("NDE Error: unable to read record in reindex!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
free(coopSave);
|
||||
|
||||
if (NEntries != SecIndex->index->NEntries) {
|
||||
#ifdef WIN32
|
||||
MessageBox(NULL, L"Secindex->NEntries desynchronized in reindex", L"Oops", 16);
|
||||
#else
|
||||
printf("NDE Error: Secindex->NEntries desynchronized in reindex!\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
pTable->DeleteScanner(s);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Index::SetCooperative(int Idx, int secpos)
|
||||
{
|
||||
if (Idx < NEntries && Idx >= 0)
|
||||
IndexTable[Idx*2+1] = secpos;
|
||||
else
|
||||
{
|
||||
#ifdef WIN32
|
||||
MessageBox(NULL, L"Cooperative update outside range", L"Oops", 16);
|
||||
#else
|
||||
printf("NDE Error: cooperative update outside range!\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Index::GetCooperative(int Idx)
|
||||
{
|
||||
if (Idx < NEntries && Idx >= 0)
|
||||
return IndexTable[Idx*2+1];
|
||||
else
|
||||
{
|
||||
#ifdef WIN32
|
||||
MessageBox(NULL, L"Cooperative request outside range", L"Oops", 16);
|
||||
#else
|
||||
printf("NDE Error: cooperative request outside range!\n");
|
||||
#endif
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Index::NeedFix() {
|
||||
for (int i=NUM_SPECIAL_RECORDS;i<NEntries;i++) {
|
||||
if (IndexTable[i*2+1] <= 0) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Index::UpdateMe(Index *Me, int NewIdx, int OldIdx)
|
||||
{
|
||||
int j=NewIdx > OldIdx ? -1 : 1;
|
||||
for (int i=min(NewIdx, OldIdx);i<=max(NewIdx, OldIdx)&&i<NEntries;i++)
|
||||
{
|
||||
if (i == NewIdx) continue;
|
||||
int v = GetCooperative(i);
|
||||
IndexField *f = SecIndex;
|
||||
while (f->index->SecIndex->index != this)
|
||||
{
|
||||
v = f->index->GetCooperative(v);
|
||||
f = f->index->SecIndex;
|
||||
}
|
||||
Me->SetCooperative(v, Me->GetCooperative(v)+j);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Field *Index::QuickFindField(unsigned char Idx, int Pos)
|
||||
{
|
||||
int ThisPos = Pos;
|
||||
|
||||
while (ThisPos)
|
||||
{
|
||||
Vfseek(TableHandle, ThisPos, SEEK_SET);
|
||||
Field entry(ThisPos);
|
||||
uint32_t next_pos;
|
||||
entry.ReadField(pTable, ThisPos, true, &next_pos);
|
||||
if (entry.GetFieldId() == Idx)
|
||||
{
|
||||
return entry.ReadField(pTable, ThisPos);
|
||||
}
|
||||
ThisPos = next_pos;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// Dynamic qsort (i definitly rule)
|
||||
int Index::FindSortedPlace(Field *thisField, int curIdx, int *laststate, int start)
|
||||
{
|
||||
return FindSortedPlaceEx(thisField, curIdx, laststate, start, COMPARE_MODE_EXACT);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
// and here again ugly switch
|
||||
int Index::FindSortedPlaceEx(Field *thisField, int curIdx, int *laststate, int start, int comp_mode)
|
||||
{
|
||||
int top=start != QFIND_ENTIRE_SCOPE ? start : NUM_SPECIAL_RECORDS;
|
||||
int bottom=NEntries-1;
|
||||
int compEntry = 0;
|
||||
int cePos = 0;
|
||||
Field *compField=NULL;
|
||||
int i = 0;
|
||||
Field *cfV=NULL;
|
||||
|
||||
if (NEntries <= NUM_SPECIAL_RECORDS) return NUM_SPECIAL_RECORDS;
|
||||
switch(comp_mode)
|
||||
{
|
||||
case COMPARE_MODE_EXACT:
|
||||
while (bottom-top >= 1)
|
||||
{
|
||||
compEntry=(bottom-top)/2+top;
|
||||
if (compEntry == curIdx) compEntry++;
|
||||
if (compEntry == bottom) break;
|
||||
cePos = Get(compEntry);
|
||||
if (!cePos) bottom = compEntry;
|
||||
else
|
||||
{
|
||||
compField = QuickFindField(Id, Get(compEntry));
|
||||
cfV = compField;
|
||||
if (!thisField)
|
||||
{
|
||||
if (!compField) i = 0;
|
||||
else i = 1;
|
||||
}
|
||||
else i = thisField->Compare(cfV);
|
||||
switch (i)
|
||||
{
|
||||
case 1:
|
||||
top = compEntry+1;
|
||||
break;
|
||||
case -1:
|
||||
bottom = compEntry-1;
|
||||
break;
|
||||
case 0:
|
||||
*laststate=0;
|
||||
delete compField;
|
||||
return compEntry+1;
|
||||
}
|
||||
delete compField;
|
||||
}
|
||||
}
|
||||
compEntry=(bottom-top)/2+top;
|
||||
if (compEntry == curIdx) return curIdx;
|
||||
compField = QuickFindField(Id, Get(compEntry));
|
||||
cfV = compField;
|
||||
if (thisField) *laststate = thisField->Compare(cfV);
|
||||
else
|
||||
{
|
||||
if (!compField) *laststate = 0;
|
||||
else *laststate = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case COMPARE_MODE_CONTAINS:
|
||||
while (bottom-top >= 1)
|
||||
{
|
||||
compEntry=(bottom-top)/2+top;
|
||||
if (compEntry == curIdx) compEntry++;
|
||||
if (compEntry == bottom) break;
|
||||
cePos = Get(compEntry);
|
||||
if (!cePos) bottom = compEntry;
|
||||
else
|
||||
{
|
||||
compField = QuickFindField(Id, Get(compEntry));
|
||||
cfV = compField;
|
||||
if (!thisField)
|
||||
{
|
||||
if (!compField) i = 0;
|
||||
else i = 1;
|
||||
}
|
||||
else i = thisField->Contains(cfV);
|
||||
switch (i)
|
||||
{
|
||||
case 1:
|
||||
top = compEntry+1;
|
||||
break;
|
||||
case -1:
|
||||
bottom = compEntry-1;
|
||||
break;
|
||||
case 0:
|
||||
*laststate=0;
|
||||
delete compField;
|
||||
return compEntry+1;
|
||||
}
|
||||
if (compField)
|
||||
{
|
||||
delete compField;
|
||||
}
|
||||
}
|
||||
}
|
||||
compEntry=(bottom-top)/2+top;
|
||||
if (compEntry == curIdx) return curIdx;
|
||||
compField = QuickFindField(Id, Get(compEntry));
|
||||
cfV = compField;
|
||||
if (thisField) *laststate = thisField->Contains(cfV);
|
||||
else
|
||||
{
|
||||
if (!compField) *laststate = 0;
|
||||
else *laststate = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case COMPARE_MODE_STARTS:
|
||||
while (bottom-top >= 1)
|
||||
{
|
||||
compEntry=(bottom-top)/2+top;
|
||||
if (compEntry == curIdx) compEntry++;
|
||||
if (compEntry == bottom) break;
|
||||
cePos = Get(compEntry);
|
||||
if (!cePos) bottom = compEntry;
|
||||
else
|
||||
{
|
||||
compField = QuickFindField(Id, Get(compEntry));
|
||||
cfV = compField;
|
||||
if (!thisField)
|
||||
{
|
||||
if (!compField) i = 0;
|
||||
else i = 1;
|
||||
}
|
||||
else i = thisField->Starts(cfV);
|
||||
switch (i)
|
||||
{
|
||||
case 1:
|
||||
top = compEntry+1;
|
||||
break;
|
||||
case -1:
|
||||
bottom = compEntry-1;
|
||||
break;
|
||||
case 0:
|
||||
*laststate=0;
|
||||
delete compField;
|
||||
return compEntry+1;
|
||||
}
|
||||
if (compField)
|
||||
{
|
||||
delete compField;
|
||||
}
|
||||
}
|
||||
}
|
||||
compEntry=(bottom-top)/2+top;
|
||||
if (compEntry == curIdx) return curIdx;
|
||||
compField = QuickFindField(Id, Get(compEntry));
|
||||
cfV = compField;
|
||||
if (thisField) *laststate = thisField->Starts(cfV);
|
||||
else
|
||||
{
|
||||
if (!compField) *laststate = 0;
|
||||
else *laststate = 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch (*laststate)
|
||||
{
|
||||
case -1:
|
||||
delete compField;
|
||||
return compEntry;
|
||||
case 1:
|
||||
case 0:
|
||||
delete compField;
|
||||
return /*compEntry==NEntries-1 ? compEntry : */compEntry+1;
|
||||
}
|
||||
return NUM_SPECIAL_RECORDS; // we're not supposed to be here :/
|
||||
}
|
||||
|
||||
int Index::QuickFind(int Id, Field *field, int start)
|
||||
{
|
||||
return QuickFindEx(Id, field, start, COMPARE_MODE_EXACT);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Index::QuickFindEx(int Id, Field *field, int start, int comp_mode)
|
||||
{
|
||||
int laststate = 0;
|
||||
Field *compField=NULL, *cfV=NULL;
|
||||
int i = FindSortedPlaceEx(field, Id, &laststate, start, comp_mode)-1; // -1 because we don't insert but just search
|
||||
if (laststate != 0)
|
||||
return FIELD_NOT_FOUND;
|
||||
if (i < start)
|
||||
return FIELD_NOT_FOUND;
|
||||
|
||||
switch(comp_mode)
|
||||
{
|
||||
case COMPARE_MODE_CONTAINS:
|
||||
while (--i>=NUM_SPECIAL_RECORDS)
|
||||
{
|
||||
compField = QuickFindField(Id, Get(i));
|
||||
cfV = compField;
|
||||
if (field->Contains(cfV) != 0)
|
||||
{
|
||||
if (compField)
|
||||
{
|
||||
delete compField;
|
||||
}
|
||||
return i+1;
|
||||
}
|
||||
if (compField)
|
||||
{
|
||||
delete compField;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case COMPARE_MODE_EXACT:
|
||||
while (--i>=NUM_SPECIAL_RECORDS)
|
||||
{
|
||||
compField = QuickFindField(Id, Get(i));
|
||||
cfV = compField;
|
||||
if (field->Compare(cfV) != 0)
|
||||
{
|
||||
if (compField)
|
||||
{
|
||||
delete compField;
|
||||
}
|
||||
return i+1;
|
||||
}
|
||||
if (compField)
|
||||
{
|
||||
delete compField;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case COMPARE_MODE_STARTS:
|
||||
while (--i>=NUM_SPECIAL_RECORDS)
|
||||
{
|
||||
compField = QuickFindField(Id, Get(i));
|
||||
cfV = compField;
|
||||
if (field->Starts(cfV) != 0)
|
||||
{
|
||||
delete compField;
|
||||
return i+1;
|
||||
}
|
||||
delete compField;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return i+1;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Index::TranslateIndex(int Pos, Index *index)
|
||||
{
|
||||
int v = GetCooperative(Pos);
|
||||
IndexField *f = SecIndex;
|
||||
while (f->index != this && f->index != index)
|
||||
{
|
||||
v = f->index->GetCooperative(v);
|
||||
f = f->index->SecIndex;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Index::Delete(int Idx, int Pos, Record *record)
|
||||
{
|
||||
Update(NULL, -1, Idx, Pos, record, true, false);
|
||||
Shrink();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Index::Shrink(void)
|
||||
{
|
||||
if (InChain) return;
|
||||
if (SecIndex && SecIndex->index != this) // Actually, we should never be InInsert and here, but lets cover our ass
|
||||
{
|
||||
InChain=true;
|
||||
SecIndex->index->Shrink();
|
||||
InChain=false;
|
||||
}
|
||||
NEntries--;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Index::SetGlobalLocateUpToDate(bool isUptodate) {
|
||||
if (!pTable) return;
|
||||
pTable->SetGlobalLocateUpToDate(isUptodate);
|
||||
}
|
||||
|
||||
unsigned char Index::GetId() {
|
||||
return Id;
|
||||
}
|
83
Src/nde/Index.h
Normal file
83
Src/nde/Index.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Raw Index Class Prototypes
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __RAWINDEX_H
|
||||
#define __RAWINDEX_H
|
||||
|
||||
#include <stdio.h>
|
||||
#ifdef WIN32
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include "vfs.h"
|
||||
#include "Table.h"
|
||||
|
||||
class IndexField;
|
||||
#define BLOCK_SIZE 2048 // 8192 entries blocks
|
||||
class RecordBase;
|
||||
class Index
|
||||
{
|
||||
public:
|
||||
Index(VFILE *Handle, unsigned char id, int pos, int type, bool newindex, int nentries, Table *parentTable);
|
||||
~Index();
|
||||
int Get(int Idx);
|
||||
void Set(int Idx, int P);
|
||||
|
||||
void LoadIndex(bool newindex);
|
||||
void WriteIndex(void);
|
||||
int Insert(Index *parindex, int N, bool localonly);
|
||||
int Insert(int N);
|
||||
int Update(int Idx, int Pos, RecordBase *record, bool localonly);
|
||||
int Update(Index *parindex, int paridx, int Idx, int Pos, RecordBase *record, bool forceLast, bool localonly);
|
||||
unsigned char GetId();
|
||||
|
||||
int FindSortedPlace(Field *field, int idx, int *laststate, int start);
|
||||
int FindSortedPlaceEx(Field *field, int idx, int *laststate, int start, int comp_mode);
|
||||
int MoveIndex(int idx, int newidx);
|
||||
void Colaborate(IndexField *secindex);
|
||||
void SetCooperative(int Idx, int secpos);
|
||||
int GetCooperative(int Idx);
|
||||
void UpdateMe(Index *Me, int newidx, int oldidx);
|
||||
Field *QuickFindField(unsigned char Id, int Pos);
|
||||
int QuickFind(int Id, Field *field, int start);
|
||||
int QuickFindEx(int Id, Field *field, int start, int comp_mode);
|
||||
int TranslateIndex(int Pos, Index *index);
|
||||
void Delete(int Idx, int Pos, Record *record);
|
||||
void Shrink(void);
|
||||
|
||||
void Propagate(void);
|
||||
void SetGlobalLocateUpToDate(bool isUptodate);
|
||||
int NeedFix();
|
||||
|
||||
public:
|
||||
// TODO: make these protected
|
||||
int NEntries;
|
||||
IndexField *SecIndex;
|
||||
bool locateUpToDate;
|
||||
|
||||
protected:
|
||||
VFILE *Handle;
|
||||
VFILE *TableHandle;
|
||||
Table *pTable;
|
||||
|
||||
int *IndexTable;
|
||||
size_t MaxSize;
|
||||
unsigned char Id;
|
||||
|
||||
bool InChain;
|
||||
int Position;
|
||||
bool InInsert;
|
||||
int InChainIdx;
|
||||
};
|
||||
|
||||
#endif
|
8
Src/nde/IndexField.h
Normal file
8
Src/nde/IndexField.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#ifdef __APPLE__
|
||||
#include "osx/IndexField.h"
|
||||
#elif defined(_WIN32)
|
||||
#include "win/IndexField.h"
|
||||
#elif defined(__ANDROID__)
|
||||
#include "android/IndexField.h"
|
||||
#endif
|
8
Src/nde/IndexRecord.h
Normal file
8
Src/nde/IndexRecord.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#ifdef __APPLE__
|
||||
#include "osx/IndexRecord.h"
|
||||
#elif defined(_WIN32)
|
||||
#include "win/IndexRecord.h"
|
||||
#elif defined(__ANDROID__)
|
||||
#include "android/IndexRecord.h"
|
||||
#endif
|
126
Src/nde/Int128Field.cpp
Normal file
126
Src/nde/Int128Field.cpp
Normal file
|
@ -0,0 +1,126 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Int128Field Class
|
||||
Field data layout:
|
||||
[16 bytes] value
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "nde.h"
|
||||
#include "Int128Field.h"
|
||||
#include <time.h>
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Int128Field::Int128Field(void *data)
|
||||
{
|
||||
InitField();
|
||||
Type = FIELD_INT128;
|
||||
memcpy(Value, data, 16);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Int128Field::InitField(void)
|
||||
{
|
||||
Type = FIELD_INT128;
|
||||
memset(Value, 0, 16);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Int128Field::Int128Field()
|
||||
{
|
||||
InitField();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Int128Field::~Int128Field()
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Int128Field::ReadTypedData(const uint8_t *data, size_t len)
|
||||
{
|
||||
if (len < 16) return;
|
||||
memcpy(Value, data, 16);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Int128Field::WriteTypedData(uint8_t *data, size_t len)
|
||||
{
|
||||
|
||||
if (len < 16) return;
|
||||
memcpy(data, Value, 16);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void *Int128Field::GetValue(void)
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Int128Field::SetValue(const void *Val)
|
||||
{
|
||||
memcpy(Value, Val, 16);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
size_t Int128Field::GetDataSize(void)
|
||||
{
|
||||
return 16;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Int128Field::Compare(Field *Entry)
|
||||
{
|
||||
if (!Entry) return -1;
|
||||
return memcmp(Value, ((Int128Field*)Entry)->GetValue(), 16);
|
||||
}
|
||||
|
||||
static char zerobuf[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
|
||||
//---------------------------------------------------------------------------
|
||||
bool Int128Field::ApplyFilter(Field *Data, int op)
|
||||
{
|
||||
void *p = ((Int128Field *)Data)->GetValue();
|
||||
void *d = Value;
|
||||
if (!p)
|
||||
p = zerobuf;
|
||||
if (!d)
|
||||
d = zerobuf;
|
||||
bool r;
|
||||
switch (op)
|
||||
{
|
||||
case FILTER_EQUALS:
|
||||
r = !memcmp(d, p, 16);
|
||||
break;
|
||||
case FILTER_CONTAINS:
|
||||
r = !memcmp(d, p, 16);
|
||||
break;
|
||||
case FILTER_ABOVE:
|
||||
r = (memcmp(d, p, 16) > 0);
|
||||
break;
|
||||
case FILTER_BELOW:
|
||||
r = (memcmp(d, p, 16) < 0);
|
||||
break;
|
||||
case FILTER_BELOWOREQUAL:
|
||||
r = (memcmp(d, p, 16) <= 0);
|
||||
break;
|
||||
case FILTER_ABOVEOREQUAL:
|
||||
r = (memcmp(d, p, 16) >= 0);
|
||||
break;
|
||||
case FILTER_ISEMPTY:
|
||||
r = !d || (!memcmp(d, zerobuf, 16));
|
||||
break;
|
||||
case FILTER_ISNOTEMPTY:
|
||||
r = d && (memcmp(d, zerobuf, 16));
|
||||
break;
|
||||
default:
|
||||
r = true;
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
38
Src/nde/Int128Field.h
Normal file
38
Src/nde/Int128Field.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Int128Field Class Prototypes
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef NULLSOFT_NDE_INT128FIELD_H
|
||||
#define NULLSOFT_NDE_INT128FIELD_H
|
||||
|
||||
#include "Field.h"
|
||||
|
||||
class Int128Field : public Field
|
||||
{
|
||||
protected:
|
||||
virtual void ReadTypedData(const uint8_t *, size_t len);
|
||||
virtual void WriteTypedData(uint8_t *, size_t len);
|
||||
virtual size_t GetDataSize(void);
|
||||
virtual int Compare(Field *Entry);
|
||||
virtual bool ApplyFilter(Field *Data, int op);
|
||||
void InitField(void);
|
||||
char Value[16];
|
||||
public:
|
||||
~Int128Field();
|
||||
Int128Field(void *value);
|
||||
Int128Field();
|
||||
void *GetValue(void);
|
||||
void SetValue(const void *value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
124
Src/nde/Int64Field.cpp
Normal file
124
Src/nde/Int64Field.cpp
Normal file
|
@ -0,0 +1,124 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Int64Field Class
|
||||
Field data layout:
|
||||
[8 bytes] value
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "nde.h"
|
||||
#include "Int64Field.h"
|
||||
#include <time.h>
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Int64Field::Int64Field(int64_t Val)
|
||||
{
|
||||
InitField();
|
||||
Type = FIELD_INT64;
|
||||
Value = Val;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Int64Field::InitField(void)
|
||||
{
|
||||
Type = FIELD_INT64;
|
||||
Value = 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Int64Field::Int64Field()
|
||||
{
|
||||
InitField();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Int64Field::~Int64Field()
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Int64Field::ReadTypedData(const uint8_t *data, size_t len)
|
||||
{
|
||||
CHECK_INT64(len);
|
||||
Value = *((int64_t *)data);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Int64Field::WriteTypedData(uint8_t *data, size_t len)
|
||||
{
|
||||
CHECK_INT64(len);
|
||||
*((int64_t *)data) = Value;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int64_t Int64Field::GetValue(void)
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Int64Field::SetValue(int64_t Val)
|
||||
{
|
||||
Value = Val;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
size_t Int64Field::GetDataSize(void)
|
||||
{
|
||||
return sizeof(int64_t);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Int64Field::Compare(Field *Entry)
|
||||
{
|
||||
if (!Entry) return -1;
|
||||
return GetValue() < ((Int64Field*)Entry)->GetValue() ? -1 : (GetValue() > ((Int64Field*)Entry)->GetValue() ? 1 : 0);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
bool Int64Field::ApplyFilter(Field *Data, int op)
|
||||
{
|
||||
bool r;
|
||||
switch (op)
|
||||
{
|
||||
case FILTER_EQUALS:
|
||||
r = Value == ((Int64Field *)Data)->GetValue();
|
||||
break;
|
||||
case FILTER_NOTEQUALS:
|
||||
r = Value != ((Int64Field *)Data)->GetValue();
|
||||
break;
|
||||
case FILTER_NOTCONTAINS:
|
||||
r = (bool)!(Value & ((Int64Field *)Data)->GetValue());
|
||||
break;
|
||||
case FILTER_CONTAINS:
|
||||
r = !!(Value & ((Int64Field *)Data)->GetValue());
|
||||
break;
|
||||
case FILTER_ABOVE:
|
||||
r = (bool)(Value > ((Int64Field *)Data)->GetValue());
|
||||
break;
|
||||
case FILTER_BELOW:
|
||||
r = (bool)(Value < ((Int64Field *)Data)->GetValue());
|
||||
break;
|
||||
case FILTER_BELOWOREQUAL:
|
||||
r = (bool)(Value <= ((Int64Field *)Data)->GetValue());
|
||||
break;
|
||||
case FILTER_ABOVEOREQUAL:
|
||||
r = (bool)(Value >= ((Int64Field *)Data)->GetValue());
|
||||
break;
|
||||
case FILTER_ISEMPTY:
|
||||
r = (Value == 0 || Value == -1);
|
||||
break;
|
||||
case FILTER_ISNOTEMPTY:
|
||||
r = !(Value == 0 || Value == -1);
|
||||
break;
|
||||
default:
|
||||
r = true;
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
39
Src/nde/Int64Field.h
Normal file
39
Src/nde/Int64Field.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Int64Field Class Prototypes
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef NULLSOFT_NDE_INT64FIELD_H
|
||||
#define NULLSOFT_NDE_INT64FIELD_H
|
||||
|
||||
#include "Field.h"
|
||||
|
||||
class Int64Field : public Field
|
||||
{
|
||||
protected:
|
||||
virtual void ReadTypedData(const uint8_t *, size_t len);
|
||||
virtual void WriteTypedData(uint8_t *, size_t len);
|
||||
virtual size_t GetDataSize(void);
|
||||
virtual int Compare(Field *Entry);
|
||||
virtual bool ApplyFilter(Field *Data, int op);
|
||||
void InitField(void);
|
||||
int64_t Value;
|
||||
|
||||
public:
|
||||
~Int64Field();
|
||||
Int64Field(int64_t);
|
||||
Int64Field();
|
||||
int64_t GetValue(void);
|
||||
void SetValue(int64_t);
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif
|
8
Src/nde/IntegerField.h
Normal file
8
Src/nde/IntegerField.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#ifdef __APPLE__
|
||||
#include "osx/IntegerField.h"
|
||||
#elif defined(_WIN32)
|
||||
#include "win/IntegerField.h"
|
||||
#elif defined(__ANDROID__)
|
||||
#include "android/IntegerField.h"
|
||||
#endif
|
126
Src/nde/LinkedList.cpp
Normal file
126
Src/nde/LinkedList.cpp
Normal file
|
@ -0,0 +1,126 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Double-Linked List Class
|
||||
|
||||
Caution: The entire library relies on this base class. Modify with care!
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "nde.h"
|
||||
#include "LinkedList.h"
|
||||
//---------------------------------------------------------------------------
|
||||
LinkedListEntry *LinkedListEntry::GetNext(void) const
|
||||
{
|
||||
return Next;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
LinkedListEntry *LinkedListEntry::GetPrevious(void) const
|
||||
{
|
||||
return Previous;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
LinkedListEntry::LinkedListEntry()
|
||||
{
|
||||
//Int=0;
|
||||
Next=NULL;
|
||||
Previous=NULL;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
LinkedListEntry::~LinkedListEntry()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
LinkedList::LinkedList()
|
||||
{
|
||||
Head = NULL;
|
||||
Foot = NULL;
|
||||
NElements=0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
LinkedList::~LinkedList()
|
||||
{
|
||||
while (Head)
|
||||
RemoveEntry(Head);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void LinkedList::AddEntry(LinkedListEntry *Entry, bool Cat)
|
||||
{
|
||||
#ifdef WIN32
|
||||
//EnterCriticalSection(&Critical);
|
||||
#endif
|
||||
if (!Cat)
|
||||
{
|
||||
if (Head)
|
||||
Head->Previous = Entry;
|
||||
Entry->Next = Head;
|
||||
Entry->Previous = NULL;
|
||||
Head = Entry;
|
||||
if (!Foot)
|
||||
Foot = Entry;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Foot)
|
||||
Foot->Next = Entry;
|
||||
Entry->Previous = Foot;
|
||||
Entry->Next = NULL;
|
||||
Foot = Entry;
|
||||
if (!Head)
|
||||
Head = Entry;
|
||||
}
|
||||
NElements++;
|
||||
#ifdef WIN32
|
||||
//LeaveCriticalSection(&Critical);
|
||||
#endif
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void LinkedList::RemoveEntry(LinkedListEntry *Entry)
|
||||
{
|
||||
if (!Entry) return;
|
||||
#ifdef WIN32
|
||||
//EnterCriticalSection(&Critical);
|
||||
#endif
|
||||
if (Entry->Next)
|
||||
Entry->Next->Previous = Entry->Previous;
|
||||
else
|
||||
Foot = Entry->Previous;
|
||||
if (Entry->Previous)
|
||||
Entry->Previous->Next = Entry->Next;
|
||||
else
|
||||
Head = Entry->Next;
|
||||
|
||||
if (NElements > 0)
|
||||
{
|
||||
delete Entry;
|
||||
NElements--;
|
||||
}
|
||||
#ifdef WIN32
|
||||
//LeaveCriticalSection(&Critical);
|
||||
#endif
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void LinkedList::WalkList(WalkListProc WalkProc, int ID, void *Data1, void *Data2)
|
||||
{
|
||||
if (!WalkProc) return;
|
||||
LinkedListEntry *Entry = Head;
|
||||
while (Entry)
|
||||
{
|
||||
if (!WalkProc(Entry, ID, Data1, Data2)) break;
|
||||
Entry = Entry->Next;
|
||||
}
|
||||
}
|
82
Src/nde/LinkedList.h
Normal file
82
Src/nde/LinkedList.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Double-Linked List Class Prototypes
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __LINKEDLIST_H
|
||||
#define __LINKEDLIST_H
|
||||
|
||||
class LinkedListEntry
|
||||
{
|
||||
public:
|
||||
LinkedListEntry *Next;
|
||||
LinkedListEntry *Previous;
|
||||
public:
|
||||
LinkedListEntry *GetNext() const;
|
||||
LinkedListEntry *GetPrevious() const;
|
||||
LinkedListEntry();
|
||||
virtual ~LinkedListEntry();
|
||||
};
|
||||
|
||||
template <class T> class VListEntry : public LinkedListEntry
|
||||
{
|
||||
public:
|
||||
void SetVal(T val)
|
||||
{
|
||||
Val = val;
|
||||
}
|
||||
T GetVal(void)
|
||||
{
|
||||
return Val;
|
||||
}
|
||||
|
||||
private:
|
||||
T Val;
|
||||
};
|
||||
|
||||
template <class T> class PListEntry : public LinkedListEntry
|
||||
{
|
||||
public:
|
||||
void SetVal(T *val)
|
||||
{
|
||||
Val = val;
|
||||
}
|
||||
T *GetVal(void)
|
||||
{
|
||||
return Val;
|
||||
}
|
||||
|
||||
private:
|
||||
T *Val;
|
||||
};
|
||||
|
||||
|
||||
typedef bool (*WalkListProc)(LinkedListEntry *Entry, int, void*, void*);
|
||||
|
||||
class LinkedList
|
||||
{
|
||||
protected:
|
||||
int NElements;
|
||||
LinkedListEntry *Head;
|
||||
LinkedListEntry *Foot;
|
||||
|
||||
public:
|
||||
LinkedList();
|
||||
~LinkedList();
|
||||
void AddEntry(LinkedListEntry *Entry, bool Cat);
|
||||
void RemoveEntry(LinkedListEntry *Entry);
|
||||
|
||||
void WalkList(WalkListProc WalkProc, int ID, void *Data1, void *Data2);
|
||||
int GetNElements(void) { return NElements; }
|
||||
LinkedListEntry *GetHead(void) { return Head; }
|
||||
LinkedListEntry *GetFoot(void) { return Foot; }
|
||||
};
|
||||
|
||||
#endif
|
84
Src/nde/NDEString.cpp
Normal file
84
Src/nde/NDEString.cpp
Normal file
|
@ -0,0 +1,84 @@
|
|||
#include "NDEString.h"
|
||||
#include "foundation/error.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
typedef BOOL (WINAPI *HEAPSETINFORMATION)(HANDLE HeapHandle, HEAP_INFORMATION_CLASS HeapInformationClass, PVOID HeapInformation, SIZE_T HeapInformationLength);
|
||||
|
||||
static HANDLE string_heap=0;
|
||||
static HMODULE kernel=0;
|
||||
extern "C" void NDE_HeapInit()
|
||||
{
|
||||
if (!string_heap)
|
||||
{
|
||||
string_heap=HeapCreate(0, 0, 0);
|
||||
kernel = LoadLibraryW(L"kernel32.dll");
|
||||
if (kernel)
|
||||
{
|
||||
HEAPSETINFORMATION hsi = (HEAPSETINFORMATION)GetProcAddress(kernel, "HeapSetInformation");
|
||||
if (hsi)
|
||||
{
|
||||
ULONG argh = 2;
|
||||
hsi(string_heap, HeapCompatibilityInformation, &argh, sizeof(ULONG));
|
||||
}
|
||||
}
|
||||
NXStringSetHeap(string_heap);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void NDE_HeapQuit()
|
||||
{
|
||||
if (kernel)
|
||||
FreeLibrary(kernel);
|
||||
}
|
||||
|
||||
nx_string_t ndestring_get_string(wchar_t *str)
|
||||
{
|
||||
if (!str)
|
||||
return 0;
|
||||
nx_string_t self = (nx_string_t)((uint8_t *)str - sizeof(size_t) - sizeof(size_t));
|
||||
return self;
|
||||
}
|
||||
|
||||
wchar_t *ndestring_wcsdup(const wchar_t *str)
|
||||
{
|
||||
NDE_HeapInit();
|
||||
if (!str)
|
||||
return 0;
|
||||
nx_string_t value;
|
||||
if (NXStringCreateWithUTF16(&value, str) != NErr_Success)
|
||||
return 0;
|
||||
return value->string;
|
||||
}
|
||||
|
||||
wchar_t *ndestring_wcsndup(const wchar_t *str, size_t len)
|
||||
{
|
||||
NDE_HeapInit();
|
||||
if (!str)
|
||||
return 0;
|
||||
nx_string_t value;
|
||||
if (NXStringCreateWithBytes(&value, str, len*2, nx_charset_utf16le) != NErr_Success)
|
||||
return 0;
|
||||
return value->string;
|
||||
}
|
||||
|
||||
wchar_t *ndestring_malloc(size_t str_size)
|
||||
{
|
||||
NDE_HeapInit();
|
||||
nx_string_t value=NXStringMalloc((str_size+1)/2 - 1);
|
||||
if (!value)
|
||||
return 0;
|
||||
return value->string;
|
||||
}
|
||||
|
||||
void ndestring_release(wchar_t *str)
|
||||
{
|
||||
nx_string_t value = ndestring_get_string(str);
|
||||
NXStringRelease(value);
|
||||
}
|
||||
|
||||
void ndestring_retain(wchar_t *str)
|
||||
{
|
||||
nx_string_t value = ndestring_get_string(str);
|
||||
NXStringRetain(value);
|
||||
}
|
31
Src/nde/NDEString.h
Normal file
31
Src/nde/NDEString.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
Ben Allison benski@winamp.com Nov 14 2007
|
||||
Simple reference counted string, to avoid a whole bunch of _wcsdup's in NDE and ml_local
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "foundation/types.h"
|
||||
#include "nx/nxstring.h"
|
||||
|
||||
enum
|
||||
{
|
||||
STRING_IS_WCHAR=0,
|
||||
STRING_IS_NDESTRING=1,
|
||||
};
|
||||
|
||||
#include "nde_defines.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
NDE_API wchar_t *ndestring_wcsdup(const wchar_t *str);
|
||||
NDE_API wchar_t *ndestring_wcsndup(const wchar_t *str, size_t n);
|
||||
NDE_API wchar_t *ndestring_malloc(size_t str_size);
|
||||
NDE_API void ndestring_release(wchar_t *str);
|
||||
NDE_API void ndestring_retain(wchar_t *str);
|
||||
NDE_API nx_string_t ndestring_get_string(wchar_t *str);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
8
Src/nde/Query.h
Normal file
8
Src/nde/Query.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#ifdef __APPLE__
|
||||
#include "osx/Query.h"
|
||||
#elif defined(_WIN32)
|
||||
#include "win/Query.h"
|
||||
#elif defined(__ANDROID__)
|
||||
#include "android/Query.h"
|
||||
#endif
|
8
Src/nde/Record.h
Normal file
8
Src/nde/Record.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#ifdef __APPLE__
|
||||
#include "osx/Record.h"
|
||||
#elif defined(_WIN32)
|
||||
#include "win/Record.h"
|
||||
#elif defined(__ANDROID__)
|
||||
#include "android/Record.h"
|
||||
#endif
|
8
Src/nde/Scanner.h
Normal file
8
Src/nde/Scanner.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#ifdef __APPLE__
|
||||
#include "osx/Scanner.h"
|
||||
#elif defined(_WIN32)
|
||||
#include "win/Scanner.h"
|
||||
#elif defined(__ANDROID__)
|
||||
#include "android/Scanner.h"
|
||||
#endif
|
8
Src/nde/StringField.h
Normal file
8
Src/nde/StringField.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#ifdef __APPLE__
|
||||
#include "osx/StringField.h"
|
||||
#elif defined(_WIN32)
|
||||
#include "win/StringField.h"
|
||||
#elif defined(__ANDROID__)
|
||||
#include "android/StringField.h"
|
||||
#endif
|
8
Src/nde/Table.h
Normal file
8
Src/nde/Table.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#ifdef __APPLE__
|
||||
#include "osx/Table.h"
|
||||
#elif defined(_WIN32)
|
||||
#include "win/Table.h"
|
||||
#elif defined(__ANDROID__)
|
||||
#include "android/Table.h"
|
||||
#endif
|
8
Src/nde/Vfs.h
Normal file
8
Src/nde/Vfs.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#ifdef __APPLE__
|
||||
#include "osx/Vfs.h"
|
||||
#elif defined(_WIN32)
|
||||
#include "win/Vfs.h"
|
||||
#elif defined(__ANDROID__)
|
||||
#include "android/vfs.h"
|
||||
#endif
|
79
Src/nde/android/Binary32Field.cpp
Normal file
79
Src/nde/android/Binary32Field.cpp
Normal file
|
@ -0,0 +1,79 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Binary32Field Class
|
||||
Field data layout:
|
||||
[4 bytes] length
|
||||
[length bytes] binary data
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "../nde.h"
|
||||
#include "Binary32Field.h"
|
||||
#include "../ndestring.h"
|
||||
//---------------------------------------------------------------------------
|
||||
Binary32Field::Binary32Field(const uint8_t *_Data, size_t len) : BinaryField(_Data, len)
|
||||
{
|
||||
InitField();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Binary32Field::InitField(void)
|
||||
{
|
||||
Type = FIELD_BINARY32;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Binary32Field::Binary32Field()
|
||||
{
|
||||
InitField();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Binary32Field::ReadTypedData(const uint8_t *data, size_t len)
|
||||
{
|
||||
uint32_t c;
|
||||
size_t pos = 0;
|
||||
|
||||
CHECK_INT(len); //len-=4;
|
||||
c = GET_INT(); pos += 4;
|
||||
if (c && c<=len)
|
||||
{
|
||||
Size = c;
|
||||
ndestring_release((ndestring_t)Data);
|
||||
Data = (uint8_t *)ndestring_malloc(c);
|
||||
GET_BINARY(Data, data, c, pos);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Binary32Field::WriteTypedData(uint8_t *data, size_t len)
|
||||
{
|
||||
uint32_t c;
|
||||
size_t pos = 0;
|
||||
|
||||
CHECK_INT(len); //len-=4;
|
||||
|
||||
if (Data && Size<=len)
|
||||
{
|
||||
c = (uint32_t)Size;
|
||||
PUT_INT(c); pos += 4;
|
||||
if (Data)
|
||||
PUT_BINARY(data, (unsigned char*)Data, c, pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
PUT_INT(0);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
size_t Binary32Field::GetDataSize(void)
|
||||
{
|
||||
if (!Data) return 4;
|
||||
return Size + 4;
|
||||
}
|
33
Src/nde/android/Binary32Field.h
Normal file
33
Src/nde/android/Binary32Field.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Binary32Field Class Prototypes
|
||||
|
||||
Android (linux) implementation
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __NDE_BINARY32FIELD_H
|
||||
#define __NDE_BINARY32FIELD_H
|
||||
|
||||
#include "BinaryField.h"
|
||||
#include <foundation/types.h>
|
||||
|
||||
class Binary32Field : public BinaryField
|
||||
{
|
||||
protected:
|
||||
virtual void ReadTypedData(const uint8_t *, size_t len);
|
||||
virtual void WriteTypedData(uint8_t *, size_t len);
|
||||
virtual size_t GetDataSize(void);
|
||||
void InitField(void);
|
||||
|
||||
public:
|
||||
Binary32Field(const uint8_t *Data, size_t len);
|
||||
Binary32Field();
|
||||
};
|
||||
|
||||
#endif
|
173
Src/nde/android/BinaryField.cpp
Normal file
173
Src/nde/android/BinaryField.cpp
Normal file
|
@ -0,0 +1,173 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
BinaryField Class
|
||||
Field data layout:
|
||||
[2 bytes] length
|
||||
[length bytes] binary data
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "../nde.h"
|
||||
#include "BinaryField.h"
|
||||
#include "../NDEString.h"
|
||||
//---------------------------------------------------------------------------
|
||||
BinaryField::BinaryField(const uint8_t *_Data, int len)
|
||||
{
|
||||
InitField();
|
||||
Type = FIELD_BINARY;
|
||||
if (_Data && len > 0)
|
||||
{
|
||||
Data = (uint8_t *)ndestring_malloc(len);
|
||||
memcpy(Data, _Data, len);
|
||||
Size = len;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void BinaryField::InitField(void)
|
||||
{
|
||||
Type = FIELD_BINARY;
|
||||
Data = NULL;
|
||||
Size = 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
BinaryField::BinaryField()
|
||||
{
|
||||
InitField();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
BinaryField::~BinaryField()
|
||||
{
|
||||
ndestring_release((ndestring_t)Data);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void BinaryField::ReadTypedData(const uint8_t *data, size_t len)
|
||||
{
|
||||
unsigned short c;
|
||||
int pos = 0;
|
||||
|
||||
CHECK_SHORT(len);
|
||||
|
||||
c = GET_SHORT(); pos += 2;
|
||||
if (c && c<=len)
|
||||
{
|
||||
Size = c;
|
||||
ndestring_release((ndestring_t)Data);
|
||||
Data = (uint8_t *)ndestring_malloc(c);
|
||||
GET_BINARY(Data, data, c, pos);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void BinaryField::WriteTypedData(uint8_t *data, size_t len)
|
||||
{
|
||||
size_t pos = 0;
|
||||
|
||||
CHECK_SHORT(len);
|
||||
|
||||
if (Data && Size<=len)
|
||||
{
|
||||
unsigned short c = (unsigned short)Size;
|
||||
PUT_SHORT(c); pos += 2;
|
||||
if (Data)
|
||||
PUT_BINARY(data, (unsigned char*)Data, c, pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
PUT_SHORT(0);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
const uint8_t *BinaryField::GetData(size_t *len)
|
||||
{
|
||||
if (len)
|
||||
*len = Size;
|
||||
return Data;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void BinaryField::SetData(const uint8_t *_Data, size_t len)
|
||||
{
|
||||
if (!_Data || !len) return;
|
||||
ndestring_release((ndestring_t)Data);
|
||||
Size = 0;
|
||||
Data = (uint8_t *)ndestring_malloc(len);
|
||||
memcpy(Data, _Data, len);
|
||||
Size = len;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
size_t BinaryField::GetDataSize(void)
|
||||
{
|
||||
if (!Data) return 2;
|
||||
return Size + 2;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int BinaryField::Compare(Field *Entry)
|
||||
{
|
||||
if (!Entry) return -1;
|
||||
size_t compare_length;
|
||||
const uint8_t *compare_data = ((BinaryField*)Entry)->GetData(&compare_length);
|
||||
return memcmp(Data, compare_data, min(compare_length, Size));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
bool BinaryField::ApplyFilter(Field *FilterData, int op)
|
||||
{
|
||||
size_t l, s;
|
||||
const uint8_t *p = ((BinaryField *)FilterData)->GetData(&l);
|
||||
const uint8_t *d = GetData(&s);
|
||||
if (!p)
|
||||
p = (const uint8_t *)"";
|
||||
if (!d)
|
||||
d = (const uint8_t *)"";
|
||||
bool r;
|
||||
switch (op)
|
||||
{
|
||||
case FILTER_EQUALS:
|
||||
if (l != s)
|
||||
r = false;
|
||||
else
|
||||
r = !memcmp(d, p, min(s, l));
|
||||
break;
|
||||
case FILTER_CONTAINS:
|
||||
if (l > s)
|
||||
r = FALSE;
|
||||
else
|
||||
r = !!memmem(d, s, p, l);
|
||||
break;
|
||||
case FILTER_ABOVE:
|
||||
r = (memcmp(d, p, min(s, l)) > 0);
|
||||
break;
|
||||
case FILTER_BELOW:
|
||||
r = (memcmp(d, p, min(s, l)) < 0);
|
||||
break;
|
||||
case FILTER_BELOWOREQUAL:
|
||||
r = (memcmp(d, p, min(s, l)) <= 0);
|
||||
break;
|
||||
case FILTER_ABOVEOREQUAL:
|
||||
r = (memcmp(d, p, min(s, l)) >= 0);
|
||||
break;
|
||||
case FILTER_ISEMPTY:
|
||||
r = (s == 0);
|
||||
break;
|
||||
case FILTER_ISNOTEMPTY:
|
||||
r = (s != 0);
|
||||
break;
|
||||
default:
|
||||
r = true;
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
38
Src/nde/android/BinaryField.h
Normal file
38
Src/nde/android/BinaryField.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
BinaryField Class Prototypes
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __BINARYFIELD_H
|
||||
#define __BINARYFIELD_H
|
||||
|
||||
#include "../Field.h"
|
||||
#include <foundation/types.h>
|
||||
class BinaryField : public Field
|
||||
{
|
||||
protected:
|
||||
virtual void ReadTypedData(const uint8_t *, size_t len);
|
||||
virtual void WriteTypedData(uint8_t *, size_t len);
|
||||
virtual size_t GetDataSize(void);
|
||||
virtual int Compare(Field *Entry);
|
||||
virtual bool ApplyFilter(Field *Data, int flags);
|
||||
void InitField(void);
|
||||
uint8_t *Data;
|
||||
size_t Size;
|
||||
|
||||
public:
|
||||
~BinaryField();
|
||||
BinaryField(const uint8_t *Data, int len);
|
||||
BinaryField();
|
||||
const uint8_t *GetData(size_t *len);
|
||||
void SetData(const uint8_t *Data, size_t len);
|
||||
};
|
||||
|
||||
#endif
|
175
Src/nde/android/ColumnField.cpp
Normal file
175
Src/nde/android/ColumnField.cpp
Normal file
|
@ -0,0 +1,175 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
ColumnField Class
|
||||
Android (linux) implementation
|
||||
|
||||
Field data layout:
|
||||
[1 byte] Field Type
|
||||
[1 byte] Unused (maybe convert to 'searchable')
|
||||
[1 byte] Name Length
|
||||
[Name Length bytes] Name (UTF-8)
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "ColumnField.h"
|
||||
#include "../NDEString.h"
|
||||
#include "../nde.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
ColumnField::ColumnField(unsigned char FieldID, const char *FieldName, unsigned char FieldType, Table *parentTable)
|
||||
{
|
||||
InitField();
|
||||
Type = FIELD_COLUMN;
|
||||
MyType = FieldType;
|
||||
Name = ndestring_wcsdup(FieldName);
|
||||
ID = FieldID;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void ColumnField::InitField(void)
|
||||
{
|
||||
searchable = false;
|
||||
MyType = FIELD_UNKNOWN;
|
||||
Type = FIELD_COLUMN;
|
||||
Name = NULL;
|
||||
ID = 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
ColumnField::ColumnField()
|
||||
{
|
||||
InitField();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
ColumnField::~ColumnField()
|
||||
{
|
||||
if (Name) free(Name);
|
||||
}
|
||||
|
||||
void ColumnField::SetSearchable(bool val)
|
||||
{
|
||||
searchable=val;
|
||||
}
|
||||
|
||||
bool ColumnField::IsSearchableField() const
|
||||
{
|
||||
return searchable;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void ColumnField::ReadTypedData(const uint8_t *data, size_t len)
|
||||
{
|
||||
unsigned char c;
|
||||
int pos=0;
|
||||
|
||||
// [1 byte] Field Type
|
||||
CHECK_CHAR(len);
|
||||
MyType = GET_CHAR();
|
||||
pos++;
|
||||
|
||||
// [1 byte] unused
|
||||
CHECK_CHAR(len);
|
||||
//cut: indexUnique = (BOOL)GET_CHAR();
|
||||
pos++;
|
||||
|
||||
// [1 byte] string length
|
||||
CHECK_CHAR(len);
|
||||
c = GET_CHAR();
|
||||
pos++;
|
||||
|
||||
if (c)
|
||||
{
|
||||
CHECK_BIN(len, c);
|
||||
Name = ndestring_wcsndup((const char *)(data+pos), c);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void ColumnField::WriteTypedData(uint8_t *data, size_t len)
|
||||
{
|
||||
int pos = 0;
|
||||
|
||||
// [1 byte] Field Type
|
||||
CHECK_CHAR(len);
|
||||
PUT_CHAR(MyType);
|
||||
pos++;
|
||||
|
||||
// [1 byte] unused
|
||||
CHECK_CHAR(len);
|
||||
PUT_CHAR(0/*(char)indexUnique*/);
|
||||
pos++;
|
||||
|
||||
CHECK_CHAR(len);
|
||||
if (Name)
|
||||
{
|
||||
int string_length = strlen(Name);
|
||||
if (string_length)
|
||||
{
|
||||
PUT_CHAR(string_length);
|
||||
pos++;
|
||||
|
||||
CHECK_BIN(len, string_length);
|
||||
PUT_BINARY(data, (const uint8_t *)Name, string_length, pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
PUT_CHAR(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PUT_CHAR(0);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
unsigned char ColumnField::GetDataType(void)
|
||||
{
|
||||
return MyType;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void ColumnField::SetDataType(unsigned char type)
|
||||
{
|
||||
if ((MyType == FIELD_INTEGER || MyType == FIELD_BOOLEAN || MyType == FIELD_DATETIME || MyType == FIELD_LENGTH) &&
|
||||
(type == FIELD_INTEGER || type == FIELD_BOOLEAN || type == FIELD_DATETIME || type == FIELD_LENGTH)) {
|
||||
MyType = type;
|
||||
}
|
||||
// going from string to filename or filename to string is OK
|
||||
if ((MyType == FIELD_FILENAME && type == FIELD_STRING)
|
||||
|| (MyType == FIELD_STRING && type == FIELD_FILENAME))
|
||||
{
|
||||
MyType = type;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
char *ColumnField::GetFieldName(void)
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
size_t ColumnField::GetDataSize(void)
|
||||
{
|
||||
size_t s=3;
|
||||
if (Name)
|
||||
{
|
||||
s+=strlen(Name);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int ColumnField::Compare(Field * /*Entry*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
47
Src/nde/android/ColumnField.h
Normal file
47
Src/nde/android/ColumnField.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
ColumnField Class Prototypes
|
||||
|
||||
Android (linux) implementation
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __COLUMNFIELD_H
|
||||
#define __COLUMNFIELD_H
|
||||
|
||||
#include "../Field.h"
|
||||
#include "../LinkedList.h"
|
||||
#include "Table.h"
|
||||
|
||||
#include "Scanner.h"
|
||||
|
||||
class ColumnField : public Field
|
||||
{
|
||||
public:
|
||||
ColumnField(unsigned char FieldID, const char *FieldName, unsigned char FieldType, Table *parentTable);
|
||||
ColumnField();
|
||||
~ColumnField();
|
||||
virtual void ReadTypedData(const uint8_t *, size_t len);
|
||||
virtual void WriteTypedData(uint8_t *, size_t len);
|
||||
virtual size_t GetDataSize(void);
|
||||
virtual int Compare(Field *Entry);
|
||||
void InitField(void);
|
||||
void SetDataType(unsigned char type);
|
||||
bool IsSearchableField() const;
|
||||
void SetSearchable(bool val);
|
||||
public:
|
||||
unsigned char GetDataType(void);
|
||||
char *GetFieldName(void); // not const because it's an NDE string
|
||||
|
||||
protected:
|
||||
bool searchable;
|
||||
char *Name;
|
||||
unsigned char MyType;
|
||||
};
|
||||
|
||||
#endif
|
128
Src/nde/android/FilenameField.cpp
Normal file
128
Src/nde/android/FilenameField.cpp
Normal file
|
@ -0,0 +1,128 @@
|
|||
#include "FilenameField.h"
|
||||
#include "../nde.h"
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
FilenameField::FilenameField(const char *Str, int strkind) : StringField(Str, strkind)
|
||||
{
|
||||
Type = FIELD_FILENAME;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
FilenameField::FilenameField()
|
||||
{
|
||||
Type = FIELD_FILENAME;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int FilenameField::Compare(Field *Entry)
|
||||
{
|
||||
if (!Entry) return -1;
|
||||
if (!CompatibleFields(Entry->GetType(), GetType()))
|
||||
return 0;
|
||||
return mystricmp_fn(GetString(), ((FilenameField*)Entry)->GetString());
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int FilenameField::Starts(Field *Entry)
|
||||
{
|
||||
if (!Entry) return -1;
|
||||
if (!CompatibleFields(Entry->GetType(), GetType()))
|
||||
return 0;
|
||||
return (mystristr_fn(GetString(), ((FilenameField*)Entry)->GetString()) == GetString());
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int FilenameField::Contains(Field *Entry)
|
||||
{
|
||||
if (!Entry) return -1;
|
||||
if (!CompatibleFields(Entry->GetType(), GetType()))
|
||||
return 0;
|
||||
return (mystristr_fn(GetString(), ((FilenameField*)Entry)->GetString()) != NULL);
|
||||
}
|
||||
|
||||
|
||||
Field *FilenameField::Clone(Table *pTable)
|
||||
{
|
||||
FilenameField *clone = new FilenameField(String, STRING_IS_NDESTRING);
|
||||
clone->Pos = FIELD_CLONE;
|
||||
clone->ID = ID;
|
||||
clone->MaxSizeOnDisk = GetDataSize();
|
||||
return clone;
|
||||
}
|
||||
|
||||
// TODO: make file system string comparison functions
|
||||
//---------------------------------------------------------------------------
|
||||
bool FilenameField::ApplyFilter(Field *Data, int op)
|
||||
{
|
||||
// TODO: maybe do this?
|
||||
if (op == FILTER_ISEMPTY || op == FILTER_ISNOTEMPTY)
|
||||
{
|
||||
bool r = (op == FILTER_ISEMPTY);
|
||||
if (!String)
|
||||
return r;
|
||||
|
||||
if (String && String[0] == 0)
|
||||
return r;
|
||||
|
||||
return !r;
|
||||
}
|
||||
//
|
||||
bool r;
|
||||
const char *p=0;
|
||||
if (Data->GetType() == FIELD_STRING)
|
||||
p = ((StringField *)Data)->GetString();
|
||||
else
|
||||
p = ((FilenameField *)Data)->GetString();
|
||||
const char *d = GetString();
|
||||
if (!p)
|
||||
p = "";
|
||||
if (!d)
|
||||
d = "";
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case FILTER_EQUALS:
|
||||
r = !nde_stricmp_fn(d, p);
|
||||
break;
|
||||
case FILTER_NOTEQUALS:
|
||||
r = !!nde_stricmp_fn(d, p);
|
||||
break;
|
||||
case FILTER_CONTAINS:
|
||||
r = (NULL != stristr_fn(d, p));
|
||||
break;
|
||||
case FILTER_NOTCONTAINS:
|
||||
r = (NULL == stristr_fn(d, p));
|
||||
break;
|
||||
case FILTER_ABOVE:
|
||||
r = (bool)(nde_stricmp_fn(d, p) > 0);
|
||||
break;
|
||||
case FILTER_ABOVEOREQUAL:
|
||||
r = (bool)(nde_stricmp_fn(d, p) >= 0);
|
||||
break;
|
||||
case FILTER_BELOW:
|
||||
r = (bool)(nde_stricmp_fn(d, p) < 0);
|
||||
break;
|
||||
case FILTER_BELOWOREQUAL:
|
||||
r = (bool)(nde_stricmp_fn(d, p) <= 0);
|
||||
break;
|
||||
case FILTER_BEGINS:
|
||||
r = (bool)(nde_strnicmp_fn(d, p, strlen(p)) == 0);
|
||||
break;
|
||||
case FILTER_ENDS:
|
||||
{
|
||||
int lenp = (int)strlen(p), lend = (int)strlen(d);
|
||||
if (lend < lenp) return 0; // too short
|
||||
r = (bool)(nde_stricmp_fn((d + lend) - lenp, p) == 0);
|
||||
}
|
||||
break;
|
||||
case FILTER_LIKE:
|
||||
r = (bool)(nde_stricmp_fn(d, p) == 0);
|
||||
break;
|
||||
default:
|
||||
r = true;
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
26
Src/nde/android/FilenameField.h
Normal file
26
Src/nde/android/FilenameField.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef NDE_FILENAMEFIELD_H
|
||||
#define NDE_FILENAMEFIELD_H
|
||||
|
||||
/*
|
||||
Mostly the same as StringField
|
||||
but this implements OS-dependent string comparisons that make sense for the file system
|
||||
*/
|
||||
|
||||
#include "../nde.h"
|
||||
#include "../NDEString.h"
|
||||
|
||||
class FilenameField : public StringField
|
||||
{
|
||||
protected:
|
||||
virtual int Compare(Field *Entry);
|
||||
virtual int Starts(Field *Entry);
|
||||
virtual int Contains(Field *Entry);
|
||||
virtual bool ApplyFilter(Field *Data, int op);
|
||||
virtual Field *Clone(Table *pTable);
|
||||
|
||||
public:
|
||||
FilenameField(const char *Str, int strkind=STRING_IS_WCHAR);
|
||||
FilenameField();
|
||||
};
|
||||
|
||||
#endif
|
142
Src/nde/android/IndexField.cpp
Normal file
142
Src/nde/android/IndexField.cpp
Normal file
|
@ -0,0 +1,142 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
IndexField Class
|
||||
Android (linux) implementation
|
||||
|
||||
Field data layout
|
||||
[4 bytes] Position
|
||||
[4 bytes] Data Type
|
||||
[1 byte] Name Length
|
||||
[Name Length bytes] Name (UTF-8)
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "../nde.h"
|
||||
#include "../ndestring.h"
|
||||
//---------------------------------------------------------------------------
|
||||
IndexField::IndexField(unsigned char id, int Pos, int type, const char *FieldName)
|
||||
{
|
||||
InitField();
|
||||
Type = FIELD_INDEX;
|
||||
Name = ndestring_wcsdup(FieldName);
|
||||
ID = id;
|
||||
Position = Pos;
|
||||
DataType = type;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void IndexField::InitField(void)
|
||||
{
|
||||
index = 0;
|
||||
Type = FIELD_INDEX;
|
||||
Name = NULL;
|
||||
ID = 0;
|
||||
Position = -1;
|
||||
DataType = FIELD_UNKNOWN;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
IndexField::IndexField()
|
||||
{
|
||||
InitField();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
IndexField::~IndexField()
|
||||
{
|
||||
ndestring_release(Name);
|
||||
delete index;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void IndexField::ReadTypedData(const uint8_t *data, size_t len)
|
||||
{
|
||||
unsigned char c;
|
||||
int pos=0;
|
||||
CHECK_INT(len);
|
||||
Position = GET_INT(); pos += 4;
|
||||
CHECK_INT(len);
|
||||
DataType = GET_INT(); pos += 4;
|
||||
CHECK_CHAR(len);
|
||||
c = GET_CHAR(); pos++;
|
||||
if (c)
|
||||
{
|
||||
CHECK_BIN(len, c);
|
||||
Name = ndestring_wcsndup((const char *)(data+pos), c);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void IndexField::WriteTypedData(uint8_t *data, size_t len)
|
||||
{
|
||||
int pos=0;
|
||||
CHECK_INT(len);
|
||||
PUT_INT(Position); pos += 4;
|
||||
|
||||
CHECK_INT(len);
|
||||
PUT_INT(DataType); pos += 4;
|
||||
CHECK_CHAR(len);
|
||||
|
||||
CHECK_CHAR(len);
|
||||
|
||||
if (Name)
|
||||
{
|
||||
int string_length = strlen(Name);
|
||||
if (string_length)
|
||||
{
|
||||
PUT_CHAR(string_length);
|
||||
pos++;
|
||||
|
||||
CHECK_BIN(len, string_length);
|
||||
PUT_BINARY(data, (const uint8_t *)Name, string_length, pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
PUT_CHAR(0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
PUT_CHAR(0);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
char *IndexField::GetIndexName(void)
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
size_t IndexField::GetDataSize(void)
|
||||
{
|
||||
size_t s=9;
|
||||
if (Name)
|
||||
{
|
||||
s+=strlen(Name);
|
||||
}
|
||||
s++;
|
||||
return s;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int IndexField::Compare(Field * /*Entry*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int IndexField::TranslateToIndex(int Id, IndexField *toindex)
|
||||
{
|
||||
if (index && toindex && toindex->index)
|
||||
return index->TranslateIndex(Id, toindex->index);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
37
Src/nde/android/IndexField.h
Normal file
37
Src/nde/android/IndexField.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
IndexField Class Prototypes
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __INDEXFIELD_H
|
||||
#define __INDEXFIELD_H
|
||||
|
||||
class IndexField : public Field
|
||||
{
|
||||
public:
|
||||
IndexField(unsigned char id, int Pos, int type, const char *FieldName);
|
||||
IndexField();
|
||||
~IndexField();
|
||||
virtual void ReadTypedData(const uint8_t *, size_t len);
|
||||
virtual void WriteTypedData(uint8_t *, size_t len);
|
||||
virtual size_t GetDataSize(void);
|
||||
virtual int Compare(Field *Entry);
|
||||
void InitField(void);
|
||||
|
||||
char *GetIndexName(void);
|
||||
int TranslateToIndex(int Id, IndexField *index);
|
||||
Index *index; // TODO: make protected
|
||||
protected:
|
||||
int Position;
|
||||
int DataType;
|
||||
char *Name;
|
||||
};
|
||||
|
||||
#endif
|
148
Src/nde/android/IndexRecord.cpp
Normal file
148
Src/nde/android/IndexRecord.cpp
Normal file
|
@ -0,0 +1,148 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
IndexRecord Class
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "IndexRecord.h"
|
||||
#include "../nde.h"
|
||||
#include <stdio.h>
|
||||
|
||||
IndexRecord::IndexRecord(int RecordPos, int insertionPoint, VFILE *TableHandle, Table *ParentTable)
|
||||
{
|
||||
InsertionPoint = insertionPoint;
|
||||
if (RecordPos != 0)
|
||||
{
|
||||
int n=0;
|
||||
uint32_t ThisPos = RecordPos;
|
||||
while (ThisPos)
|
||||
{
|
||||
if (n >= 128)
|
||||
break;
|
||||
Vfseek(TableHandle, ThisPos, SEEK_SET);
|
||||
Field Entry (ThisPos);
|
||||
Field *TypedEntry = Entry.ReadField(ParentTable, ThisPos, &ThisPos);
|
||||
|
||||
if (!TypedEntry) break; // some db error?
|
||||
|
||||
AddField(TypedEntry);
|
||||
// ThisPos = TypedEntry->GetNextFieldPos();
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IndexRecord::BuildCollaboration()
|
||||
{
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
IndexField *p = (IndexField *)*itr;
|
||||
if (p->next)
|
||||
p->index->Colaborate((IndexField *)p->next);
|
||||
else
|
||||
p->index->Colaborate((IndexField *)*Fields.begin());
|
||||
}
|
||||
}
|
||||
|
||||
bool IndexRecord::NeedFix()
|
||||
{
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
IndexField *p = (IndexField *)*itr;
|
||||
if (p->index->NeedFix())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
IndexField *IndexRecord::GetIndexByName(const char *name)
|
||||
{
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
IndexField *p = (IndexField *)*itr;
|
||||
if (!strcasecmp(p->GetIndexName(), name))
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool IndexRecord::CheckIndexing(int v)
|
||||
{
|
||||
int i = v;
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
IndexField *p = (IndexField *)*itr;
|
||||
v = p->index->GetCooperative(v);
|
||||
}
|
||||
return v == i;
|
||||
}
|
||||
|
||||
Field *RecordBase::GetField(unsigned char ID)
|
||||
{
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
IndexField *p = (IndexField *)*itr;
|
||||
if (p->GetFieldId() == ID)
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void RecordBase::AddField(Field *field)
|
||||
{
|
||||
if (!field) return;
|
||||
if (GetField(field->ID))
|
||||
return;
|
||||
|
||||
Fields.push_back(field);
|
||||
}
|
||||
|
||||
int IndexRecord::WriteFields(Table *ParentTable)
|
||||
{
|
||||
Field *previous = 0;
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
IndexField *p = (IndexField *)*itr;
|
||||
p->WriteField(ParentTable, previous, (Field *)p->next);
|
||||
previous = p;
|
||||
}
|
||||
return WriteIndex(ParentTable);
|
||||
}
|
||||
|
||||
|
||||
int IndexRecord::WriteIndex(Table *ParentTable)
|
||||
{
|
||||
int P=0;
|
||||
if (!Fields.empty())
|
||||
P=(*Fields.begin())->GetFieldPos();
|
||||
return ParentTable->index->Update(INDEX_RECORD_NUM, P, this, false);
|
||||
}
|
||||
|
||||
void RecordBase::RemoveField(Field *field)
|
||||
{
|
||||
if (!field)
|
||||
return;
|
||||
Fields.erase(field);
|
||||
delete field;
|
||||
}
|
||||
|
||||
void IndexRecord::WalkFields(FieldsWalker callback, void *context)
|
||||
{
|
||||
if (callback)
|
||||
{
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
if (!callback(this, *itr, context))
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
23
Src/nde/android/IndexRecord.h
Normal file
23
Src/nde/android/IndexRecord.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
/*
|
||||
Android (linux) implementation
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include "Record.h"
|
||||
#include <nu/PtrDeque2.h>
|
||||
class IndexField;
|
||||
class IndexRecord : public RecordBase
|
||||
{
|
||||
public:
|
||||
IndexRecord(int RecordPos, int insertionPoint, VFILE *FileHandle, Table *p);
|
||||
void BuildCollaboration();
|
||||
bool NeedFix();
|
||||
IndexField *GetIndexByName(const char *name);
|
||||
int GetColumnCount() { return Fields.size() - 1; }
|
||||
bool CheckIndexing(int v);
|
||||
int WriteFields(Table *ParentTable);
|
||||
int WriteIndex(Table *ParentTable);
|
||||
typedef bool (*FieldsWalker)(IndexRecord *record, Field *entry, void *context);
|
||||
void WalkFields(FieldsWalker callback, void *context);
|
||||
};
|
||||
|
1015
Src/nde/android/IntegerField.cpp
Normal file
1015
Src/nde/android/IntegerField.cpp
Normal file
File diff suppressed because it is too large
Load diff
93
Src/nde/android/IntegerField.h
Normal file
93
Src/nde/android/IntegerField.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
IntegerField Class Prototypes
|
||||
|
||||
Android (linux) implementation
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __INTEGERFIELD_H
|
||||
#define __INTEGERFIELD_H
|
||||
|
||||
#include <foundation/types.h>
|
||||
|
||||
class TimeParse {
|
||||
public:
|
||||
int is_relative; // ago/after/before used
|
||||
int absolute_datetime; // if not is_relative, this is the date/time, otherwise it's the resulting date/time if the query was ran now
|
||||
int absolute_hasdate; // if not, use only the time portion of absolute_datetime, the rest is now
|
||||
int absolute_hastime; // if not, use only the date portion of absolute_datetime, the rest is now
|
||||
int relative_year; // -1 = this year
|
||||
int relative_month; // -1 = this month
|
||||
int relative_day; // -1 = this day, -2 = this week
|
||||
int relative_hour; // -1 = this hour
|
||||
int relative_min; // -1 = this minute
|
||||
int relative_sec; // -1 = this second
|
||||
int relative_kwday; // not used(-1), 0 to 6 for sunday to saturday, yesterday(7), today(8), tomorrow(9)
|
||||
int offset_value; // timeago/offsetby numerical edit field
|
||||
int offset_what; // not used(-1) years(0), months(1), weeks(2), days(3), hours(4), minutes(5), seconds(6)
|
||||
int offset_whence; // not used(-1), after(0), ago/before(1)
|
||||
int offset_used; // if 1, 'time ago' / 'offset by' should be checked
|
||||
};
|
||||
|
||||
class IntegerField : public Field
|
||||
{
|
||||
protected:
|
||||
|
||||
virtual void ReadTypedData(const uint8_t *, size_t len);
|
||||
virtual void WriteTypedData(uint8_t *, size_t len);
|
||||
virtual size_t GetDataSize(void);
|
||||
virtual int Compare(Field *Entry);
|
||||
virtual bool ApplyFilter(Field *Data, int op);
|
||||
void InitField(void);
|
||||
int Value;
|
||||
|
||||
enum {
|
||||
WHAT_YEARS,
|
||||
WHAT_MONTHS,
|
||||
WHAT_WEEKS,
|
||||
WHAT_DAYS,
|
||||
WHAT_HOURS,
|
||||
WHAT_MINUTES,
|
||||
WHAT_SECONDS,
|
||||
};
|
||||
|
||||
enum {
|
||||
FROM_BARE,
|
||||
FROM_AGO,
|
||||
FROM_SINCE,
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
~IntegerField();
|
||||
IntegerField(int);
|
||||
IntegerField();
|
||||
int GetValue(void);
|
||||
void SetValue(int);
|
||||
int ApplyConversion(const char *format, TimeParse *tp=NULL);
|
||||
static int LookupToken(const char *t);
|
||||
};
|
||||
|
||||
|
||||
class DateTimeField : public IntegerField {
|
||||
public:
|
||||
DateTimeField();
|
||||
DateTimeField(int Val);
|
||||
virtual ~DateTimeField();
|
||||
};
|
||||
|
||||
class LengthField : public IntegerField {
|
||||
public:
|
||||
LengthField();
|
||||
LengthField(int Val);
|
||||
virtual ~LengthField();
|
||||
};
|
||||
|
||||
#endif
|
973
Src/nde/android/Query.cpp
Normal file
973
Src/nde/android/Query.cpp
Normal file
|
@ -0,0 +1,973 @@
|
|||
#include "../nde.h"
|
||||
#include "../NDEString.h"
|
||||
#include "Query.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
bool Scanner::Query(const char *query)
|
||||
{
|
||||
if (!query) return false;
|
||||
ndestring_release(last_query);
|
||||
last_query = ndestring_wcsdup(query);
|
||||
RemoveFilters();
|
||||
in_query_parser = 1;
|
||||
bool r = Query_Parse(query);
|
||||
|
||||
if (r == false)
|
||||
{
|
||||
if (!disable_date_resolution) RemoveFilters();
|
||||
last_query_failed = true;
|
||||
}
|
||||
in_query_parser = 0;
|
||||
Query_CleanUp();
|
||||
return r & CheckFilters();
|
||||
}
|
||||
|
||||
const char *Scanner::GetLastQuery()
|
||||
{
|
||||
return last_query;
|
||||
}
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char *token;
|
||||
int tid;
|
||||
} tokenstruct;
|
||||
|
||||
tokenstruct Tokens[] = // Feel free to add more...
|
||||
{
|
||||
{"AND", TOKEN_AND },
|
||||
{"OR", TOKEN_OR },
|
||||
{"HAS", TOKEN_CONTAINS },
|
||||
{"NOTHAS",TOKEN_NOTCONTAINS},
|
||||
{"BEGINS", TOKEN_BEGINS },
|
||||
{"ENDS", TOKEN_ENDS },
|
||||
{"ISEMPTY", TOKEN_ISEMPTY},
|
||||
{"ISNOTEMPTY",TOKEN_ISNOTEMPTY},
|
||||
{"LIKE", TOKEN_LIKE},
|
||||
{"BEGINSLIKE", TOKEN_BEGINSLIKE},
|
||||
};
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int Op;
|
||||
int Level;
|
||||
} OpLevel;
|
||||
|
||||
static int Query_ParseLength(const char *str)
|
||||
{
|
||||
int i = atoi(str);
|
||||
|
||||
const char *p;
|
||||
if ((p=strstr(str,":")))
|
||||
{
|
||||
i*=60;
|
||||
i+=atoi(++p);
|
||||
if ((p=strstr(p,":")))
|
||||
{
|
||||
i*=60;
|
||||
i+=atoi(++p);
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
our state machine
|
||||
|
||||
&, |
|
||||
----------<-------------------------<----------------------<-----------
|
||||
| |
|
||||
v ID (Col) =, >, <... ID / Data / [f] ) |
|
||||
---->(0) ----->-----> (1) ------>-----> (2) ------>------> (3) ------>-----> (4) <--
|
||||
| |^ \isempty------------->------------/ |^ | |
|
||||
| !( || ||---- | ) |
|
||||
--<-- ---------<---------------------------<-------------<-| | -->--
|
||||
&, | v [f] |
|
||||
-->--
|
||||
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
bool Scanner::Query_Parse(const char *query)
|
||||
{
|
||||
const char *p = query; // pointer on next token to read
|
||||
int size;
|
||||
int state = 0;
|
||||
int pcount = 0;
|
||||
VListEntry<OpLevel> *entry;
|
||||
|
||||
if (pstack.GetNElements() > 0)
|
||||
Query_CleanUp();
|
||||
|
||||
while (1)
|
||||
{
|
||||
p = Query_EatSpace(p);
|
||||
int t = Query_GetNextToken(p, &size, &token);
|
||||
if (t == TOKEN_UNKNOWN)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return false;
|
||||
}
|
||||
if (t == TOKEN_EOQ)
|
||||
break;
|
||||
switch (state)
|
||||
{
|
||||
case 0:
|
||||
switch (t)
|
||||
{
|
||||
case TOKEN_PAROPEN:
|
||||
state = 0;
|
||||
// check too many parenthesis open
|
||||
if (pcount == 255)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query)); // should not be _syntax_ error
|
||||
return false;
|
||||
}
|
||||
// up one level
|
||||
pcount++;
|
||||
break;
|
||||
case TOKEN_NOT:
|
||||
// push not in this level
|
||||
OpLevel o;
|
||||
o.Op = FILTER_NOT;
|
||||
o.Level = pcount;
|
||||
entry = new VListEntry<OpLevel>;
|
||||
entry->SetVal(o);
|
||||
pstack.AddEntry(entry, true);
|
||||
state = 0;
|
||||
break;
|
||||
case TOKEN_IDENTIFIER:
|
||||
state = 1;
|
||||
// create filter column
|
||||
|
||||
if (AddFilterByName(token, NULL, FILTER_NONE) == ADDFILTER_FAILED)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return false;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
switch (t)
|
||||
{
|
||||
case TOKEN_EQUAL:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_EQUALS);
|
||||
break;
|
||||
}
|
||||
case TOKEN_ABOVE:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_ABOVE);
|
||||
break;
|
||||
}
|
||||
case TOKEN_BELOW:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_BELOW);
|
||||
break;
|
||||
}
|
||||
case TOKEN_CONTAINS:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_CONTAINS);
|
||||
break;
|
||||
}
|
||||
case TOKEN_NOTCONTAINS:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_NOTCONTAINS);
|
||||
break;
|
||||
}
|
||||
case TOKEN_AOREQUAL:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_ABOVEOREQUAL);
|
||||
break;
|
||||
}
|
||||
case TOKEN_BOREQUAL:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_BELOWOREQUAL);
|
||||
break;
|
||||
}
|
||||
case TOKEN_NOTEQUAL:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_NOTEQUALS);
|
||||
break;
|
||||
}
|
||||
case TOKEN_BEGINS:
|
||||
{
|
||||
state = 2;
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_BEGINS);
|
||||
}
|
||||
break;
|
||||
case TOKEN_ENDS:
|
||||
{
|
||||
state = 2;
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_ENDS);
|
||||
}
|
||||
break;
|
||||
case TOKEN_LIKE:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_LIKE);
|
||||
break;
|
||||
}
|
||||
case TOKEN_BEGINSLIKE:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_BEGINSLIKE);
|
||||
break;
|
||||
}
|
||||
case TOKEN_ISNOTEMPTY:
|
||||
case TOKEN_ISEMPTY:
|
||||
{
|
||||
state = 3;
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(t==TOKEN_ISEMPTY ? FILTER_ISEMPTY : FILTER_ISNOTEMPTY);
|
||||
// pop all operators in this level beginning by the last inserted
|
||||
entry = (VListEntry<OpLevel> *)pstack.GetFoot();
|
||||
while (entry)
|
||||
{
|
||||
if (entry->GetVal().Level == pcount)
|
||||
{
|
||||
AddFilterOp(entry->GetVal().Op);
|
||||
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
|
||||
pstack.RemoveEntry(entry);
|
||||
entry = _entry;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (t == TOKEN_SQBRACKETOPEN)
|
||||
{
|
||||
state = 3;
|
||||
const char *s = strchr(p, ']');
|
||||
if (!s)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return false;
|
||||
}
|
||||
p = Query_EatSpace(p);
|
||||
if (*p == '[') p++;
|
||||
|
||||
char *format = ndestring_malloc((s-p+1)*sizeof(char));
|
||||
strncpy(format, p, s-p);
|
||||
format[s-p] = 0;
|
||||
|
||||
Filter *f = GetLastFilter();
|
||||
int id = f->GetId();
|
||||
ColumnField *c = GetColumnById(id);
|
||||
int tt = c ? c->GetDataType() : -1;
|
||||
if (disable_date_resolution || !c || (tt != FIELD_INTEGER && tt != FIELD_DATETIME && tt != FIELD_LENGTH && tt != FIELD_BOOLEAN))
|
||||
{
|
||||
|
||||
if (disable_date_resolution)
|
||||
{
|
||||
StringField *field = (StringField *)f->Data();
|
||||
|
||||
if (!field)
|
||||
{
|
||||
// format was used without a value, assume value is 0
|
||||
f->SetData(new StringField(""));
|
||||
entry = (VListEntry<OpLevel> *)pstack.GetFoot();
|
||||
while (entry)
|
||||
{
|
||||
if (entry->GetVal().Level == pcount)
|
||||
{
|
||||
AddFilterOp(entry->GetVal().Op);
|
||||
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
|
||||
pstack.RemoveEntry(entry);
|
||||
entry = _entry;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
field = (StringField*)f->Data();
|
||||
}
|
||||
|
||||
field->SetNDEString(format);
|
||||
ndestring_release(format);
|
||||
p = s+1;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
ndestring_release(format);
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return false;
|
||||
}
|
||||
|
||||
IntegerField *field = (IntegerField *)f->Data();
|
||||
|
||||
if (!field)
|
||||
{
|
||||
// format was used without a value, assume value is 0
|
||||
f->SetData(new IntegerField(0));
|
||||
entry = (VListEntry<OpLevel> *)pstack.GetFoot();
|
||||
while (entry)
|
||||
{
|
||||
if (entry->GetVal().Level == pcount)
|
||||
{
|
||||
AddFilterOp(entry->GetVal().Op);
|
||||
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
|
||||
pstack.RemoveEntry(entry);
|
||||
entry = _entry;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
field = (IntegerField *)f->Data();
|
||||
}
|
||||
int r = field->ApplyConversion(format);
|
||||
ndestring_release(format);
|
||||
if (!r)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return false;
|
||||
}
|
||||
p = s+1;
|
||||
continue;
|
||||
}
|
||||
// switch (t) {
|
||||
// case TOKEN_IDENTIFIER:
|
||||
else // JF> we make this relaxed, so anything is valid as a value
|
||||
{
|
||||
state = 3;
|
||||
// set filter data
|
||||
Filter *f = GetLastFilter();
|
||||
int id = f->GetId();
|
||||
ColumnField *c = GetColumnById(id);
|
||||
switch (c ? c->GetDataType() : -1)
|
||||
{
|
||||
case FIELD_DATETIME:
|
||||
if (disable_date_resolution)
|
||||
goto field_string_override;
|
||||
case FIELD_LENGTH:
|
||||
{
|
||||
int i;
|
||||
IntegerField *i_f = new IntegerField();
|
||||
i = Query_ParseLength(token);
|
||||
i_f->SetValue(i);
|
||||
f->SetData(i_f);
|
||||
}
|
||||
break;
|
||||
|
||||
case FIELD_BOOLEAN:
|
||||
case FIELD_INTEGER:
|
||||
{
|
||||
int i;
|
||||
IntegerField *i_f = new IntegerField();
|
||||
i = atoi(token);
|
||||
i_f->SetValue(i);
|
||||
f->SetData(i_f);
|
||||
}
|
||||
break;
|
||||
case FIELD_INT64:
|
||||
{
|
||||
int64_t i;
|
||||
Int64Field *i_f = new Int64Field();
|
||||
i = strtoull(token, 0, 10); // todo: Replace with own conversion and error checking
|
||||
i_f->SetValue(i);
|
||||
f->SetData(i_f);
|
||||
}
|
||||
break;
|
||||
case FIELD_FILENAME:
|
||||
{
|
||||
FilenameField *s_f = new FilenameField();
|
||||
s_f->SetNDEString(token);
|
||||
f->SetData(s_f);
|
||||
}
|
||||
break;
|
||||
case FIELD_STRING:
|
||||
field_string_override:
|
||||
{
|
||||
StringField *s_f = new StringField();
|
||||
s_f->SetNDEString(token);
|
||||
f->SetData(s_f);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return false;
|
||||
break;
|
||||
|
||||
}
|
||||
// pop all operators in this level beginning by the last inserted
|
||||
entry = (VListEntry<OpLevel> *)pstack.GetFoot();
|
||||
while (entry)
|
||||
{
|
||||
if (entry->GetVal().Level == pcount)
|
||||
{
|
||||
AddFilterOp(entry->GetVal().Op);
|
||||
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
|
||||
pstack.RemoveEntry(entry);
|
||||
entry = _entry;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// default:
|
||||
// Query_SyntaxError(p-query);
|
||||
// return false;
|
||||
// }
|
||||
break;
|
||||
case 3:
|
||||
switch (t)
|
||||
{
|
||||
case TOKEN_SQBRACKETOPEN:
|
||||
{
|
||||
const char *s = strchr(p, ']');
|
||||
if (!s)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return false;
|
||||
}
|
||||
p = Query_EatSpace(p);
|
||||
if (*p == '[') p++;
|
||||
char *format = ndestring_malloc((s-p+1)*sizeof(char));
|
||||
strncpy(format, p, s-p);
|
||||
format[s-p] = 0;
|
||||
Filter *f = GetLastFilter();
|
||||
int id = f->GetId();
|
||||
ColumnField *c = GetColumnById(id);
|
||||
int tt = c ? c->GetDataType() : -1;
|
||||
if (disable_date_resolution || !c || (tt != FIELD_INTEGER && tt != FIELD_DATETIME && tt != FIELD_LENGTH && tt != FIELD_BOOLEAN))
|
||||
{
|
||||
if (disable_date_resolution)
|
||||
{
|
||||
StringField *field = (StringField *)f->Data();
|
||||
|
||||
if (!field)
|
||||
{
|
||||
// format was used without a value, assume value is 0
|
||||
f->SetData(new StringField(""));
|
||||
entry = (VListEntry<OpLevel> *)pstack.GetFoot();
|
||||
while (entry)
|
||||
{
|
||||
if (entry->GetVal().Level == pcount)
|
||||
{
|
||||
AddFilterOp(entry->GetVal().Op);
|
||||
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
|
||||
pstack.RemoveEntry(entry);
|
||||
entry = _entry;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
field = (StringField *)f->Data();
|
||||
}
|
||||
|
||||
field->SetNDEString(format);
|
||||
ndestring_release(format);
|
||||
p = s+1;
|
||||
continue;
|
||||
}
|
||||
ndestring_release(format);
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return false;
|
||||
}
|
||||
|
||||
IntegerField *field = (IntegerField *)f->Data();
|
||||
|
||||
if (!field)
|
||||
{
|
||||
// format was used without a value, assume value is 0
|
||||
f->SetData(new IntegerField(0));
|
||||
entry = (VListEntry<OpLevel> *)pstack.GetFoot();
|
||||
while (entry)
|
||||
{
|
||||
if (entry->GetVal().Level == pcount)
|
||||
{
|
||||
AddFilterOp(entry->GetVal().Op);
|
||||
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
|
||||
pstack.RemoveEntry(entry);
|
||||
entry = _entry;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
field = (IntegerField *)f->Data();
|
||||
}
|
||||
int r = field->ApplyConversion(format);
|
||||
ndestring_release(format);
|
||||
if (!r)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return false;
|
||||
}
|
||||
p = s+1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case TOKEN_PARCLOSE:
|
||||
state = 4;
|
||||
// check parenthesis count
|
||||
if (pcount == 0)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return false;
|
||||
}
|
||||
// down one level
|
||||
pcount--;
|
||||
// pop all operators in this level, beginning by the last inserted
|
||||
while (entry)
|
||||
{
|
||||
if (entry->GetVal().Level == pcount)
|
||||
{
|
||||
AddFilterOp(entry->GetVal().Op);
|
||||
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
|
||||
pstack.RemoveEntry(entry);
|
||||
entry = _entry;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TOKEN_AND:
|
||||
{
|
||||
state = 0;
|
||||
// push and
|
||||
OpLevel o;
|
||||
o.Op = FILTER_AND;
|
||||
o.Level = pcount;
|
||||
entry = new VListEntry<OpLevel>;
|
||||
entry->SetVal(o);
|
||||
pstack.AddEntry(entry, true);
|
||||
break;
|
||||
}
|
||||
case TOKEN_OR:
|
||||
{
|
||||
state = 0;
|
||||
// push or
|
||||
OpLevel o;
|
||||
o.Op = FILTER_OR;
|
||||
o.Level = pcount;
|
||||
entry = new VListEntry<OpLevel>;
|
||||
entry->SetVal(o);
|
||||
pstack.AddEntry(entry, true);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
switch (t)
|
||||
{
|
||||
case TOKEN_AND:
|
||||
{
|
||||
state = 0;
|
||||
// push and
|
||||
OpLevel o;
|
||||
o.Op = FILTER_AND;
|
||||
o.Level = pcount;
|
||||
entry = new VListEntry<OpLevel>;
|
||||
entry->SetVal(o);
|
||||
pstack.AddEntry(entry, true);
|
||||
break;
|
||||
}
|
||||
case TOKEN_OR:
|
||||
{
|
||||
state = 0;
|
||||
// push or
|
||||
OpLevel o;
|
||||
o.Op = FILTER_OR;
|
||||
o.Level = pcount;
|
||||
entry = new VListEntry<OpLevel>;
|
||||
entry->SetVal(o);
|
||||
pstack.AddEntry(entry, true);
|
||||
break;
|
||||
}
|
||||
case TOKEN_PARCLOSE:
|
||||
state = 4;
|
||||
// check parenthesis count
|
||||
if (pcount == 0)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return false;
|
||||
}
|
||||
// down one level
|
||||
pcount--;
|
||||
// pop all operators in this level, beginning by the last inserted
|
||||
while (entry)
|
||||
{
|
||||
if (entry->GetVal().Level == pcount)
|
||||
{
|
||||
AddFilterOp(entry->GetVal().Op);
|
||||
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
|
||||
pstack.RemoveEntry(entry);
|
||||
entry = _entry;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Ahem... :/
|
||||
break;
|
||||
}
|
||||
p += size;
|
||||
}
|
||||
if (pcount > 0)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void Scanner::Query_SyntaxError(int c)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Scanner::Query_CleanUp()
|
||||
{
|
||||
while (pstack.GetNElements() > 0)
|
||||
{
|
||||
VListEntry<int> *e;
|
||||
e = (VListEntry<int> *)pstack.GetHead();
|
||||
pstack.RemoveEntry(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
const char *Scanner::Query_EatSpace(const char *p)
|
||||
{
|
||||
while (*p && *p == ' ') p++;
|
||||
return p;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
const char *Scanner::Query_ProbeNonAlphaNum(const char *p)
|
||||
{
|
||||
int inquote=0;
|
||||
while (*p && (!Query_isControlChar(*p) || (inquote)))
|
||||
{
|
||||
if (*p == '\"')
|
||||
{
|
||||
if (!inquote)
|
||||
inquote = 1;
|
||||
else
|
||||
return p+1;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Scanner::Query_isControlChar(char p)
|
||||
{
|
||||
switch (p)
|
||||
{
|
||||
case '&':
|
||||
case '|':
|
||||
case '!':
|
||||
case '(':
|
||||
case '[':
|
||||
case ')':
|
||||
case ']':
|
||||
case '>':
|
||||
case '<':
|
||||
case '=':
|
||||
case ',':
|
||||
case ' ':
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
char *Scanner::Query_ProbeAlphaNum(char *p)
|
||||
{
|
||||
while (*p && Query_isControlChar(*p)) p++;
|
||||
return p;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
char *Scanner::Query_ProbeSpace(char *p)
|
||||
{
|
||||
while (*p && *p != ' ') p++;
|
||||
return p;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Scanner::Query_LookupToken(const char *t)
|
||||
{
|
||||
for (int i=0;i<sizeof(Tokens)/sizeof(tokenstruct);i++)
|
||||
{
|
||||
if (!_stricmp(Tokens[i].token, t))
|
||||
return Tokens[i].tid;
|
||||
}
|
||||
return TOKEN_IDENTIFIER;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
int Scanner::Query_GetNextToken(const char *p, int *size, char **_token, int tokentable)
|
||||
{
|
||||
|
||||
int t = TOKEN_EOQ;
|
||||
const char *startptr = p;
|
||||
|
||||
if (!*p) return TOKEN_EOQ;
|
||||
|
||||
p = Query_EatSpace(p);
|
||||
|
||||
const char *e = Query_ProbeNonAlphaNum(p);
|
||||
|
||||
if (e != p) // We have a word
|
||||
{
|
||||
size_t token_length = e-p;
|
||||
if (*_token) ndestring_release(*_token);
|
||||
*_token = ndestring_wcsndup(p, token_length);
|
||||
if (*(*_token) == '\"' && (*_token)[token_length-1] == '\"') // check for quoted string
|
||||
{
|
||||
size_t l=token_length-2;
|
||||
if (l>0)
|
||||
{
|
||||
memcpy(*_token,(*_token)+1,l*sizeof(char));
|
||||
(*_token)[l]=0;
|
||||
Query_Unescape(*_token);
|
||||
}
|
||||
else
|
||||
(*_token)[0]=0;// we have an empty string
|
||||
}
|
||||
|
||||
switch (tokentable)
|
||||
{
|
||||
case -1:
|
||||
t = TOKEN_IDENTIFIER;
|
||||
break;
|
||||
case 0:
|
||||
t = Query_LookupToken(*_token);
|
||||
break;
|
||||
case 1:
|
||||
t = IntegerField::LookupToken(*_token);
|
||||
}
|
||||
p = e;
|
||||
}
|
||||
else // We have a symbol
|
||||
{
|
||||
switch (*p)
|
||||
{
|
||||
case '&':
|
||||
if (*(p+1) == '&') p++;
|
||||
t = TOKEN_AND;
|
||||
break;
|
||||
case '|':
|
||||
if (*(p+1) == '|') p++;
|
||||
t = TOKEN_OR;
|
||||
break;
|
||||
case '!':
|
||||
if (*(p+1) == '=')
|
||||
{
|
||||
p++;
|
||||
t = TOKEN_NOTEQUAL;
|
||||
break;
|
||||
}
|
||||
t = TOKEN_NOT;
|
||||
break;
|
||||
case '(':
|
||||
t = TOKEN_PAROPEN;
|
||||
break;
|
||||
case ')':
|
||||
t = TOKEN_PARCLOSE;
|
||||
break;
|
||||
case '[':
|
||||
t = TOKEN_SQBRACKETOPEN;
|
||||
break;
|
||||
case ']':
|
||||
t = TOKEN_SQBRACKETCLOSE;
|
||||
break;
|
||||
case ',':
|
||||
t = TOKEN_COMMA;
|
||||
break;
|
||||
case '>':
|
||||
if (*(p+1) == '=')
|
||||
{
|
||||
p++;
|
||||
t = TOKEN_AOREQUAL;
|
||||
break;
|
||||
}
|
||||
if (*(p+1) == '<')
|
||||
{
|
||||
p++;
|
||||
t = TOKEN_NOTEQUAL;
|
||||
break;
|
||||
}
|
||||
t = TOKEN_ABOVE;
|
||||
break;
|
||||
case '<':
|
||||
if (*(p+1) == '=')
|
||||
{
|
||||
p++;
|
||||
t = TOKEN_BOREQUAL;
|
||||
break;
|
||||
}
|
||||
if (*(p+1) == '>')
|
||||
{
|
||||
p++;
|
||||
t = TOKEN_NOTEQUAL;
|
||||
break;
|
||||
}
|
||||
t = TOKEN_BELOW;
|
||||
break;
|
||||
case '=':
|
||||
if (*(p+1) == '>')
|
||||
{
|
||||
p++;
|
||||
t = TOKEN_AOREQUAL;
|
||||
break;
|
||||
}
|
||||
if (*(p+1) == '<')
|
||||
{
|
||||
p++;
|
||||
t = TOKEN_BOREQUAL;
|
||||
break;
|
||||
}
|
||||
if (*(p+1) == '!')
|
||||
{
|
||||
p++;
|
||||
t = TOKEN_NOTEQUAL;
|
||||
break;
|
||||
}
|
||||
if (*(p+1) == '=') p++;
|
||||
t = TOKEN_EQUAL;
|
||||
break;
|
||||
default:
|
||||
t = TOKEN_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
*size = (int)(p - startptr);
|
||||
return t;
|
||||
}
|
||||
|
||||
static uint8_t quickhex(char c)
|
||||
{
|
||||
int hexvalue = c;
|
||||
if (hexvalue & 0x10)
|
||||
hexvalue &= ~0x30;
|
||||
else
|
||||
{
|
||||
hexvalue &= 0xF;
|
||||
hexvalue += 9;
|
||||
}
|
||||
return hexvalue;
|
||||
}
|
||||
|
||||
static uint8_t DecodeEscape(const char *&str)
|
||||
{
|
||||
uint8_t a = quickhex(*++str);
|
||||
uint8_t b = quickhex(*++str);
|
||||
str++;
|
||||
return a * 16 + b;
|
||||
}
|
||||
|
||||
static void DecodeEscapedUTF8(char *&output, const char *&input)
|
||||
{
|
||||
bool error=false;
|
||||
|
||||
while (*input == '%')
|
||||
{
|
||||
if (isxdigit(input[1]) && isxdigit(input[2]))
|
||||
{
|
||||
*output++=DecodeEscape(input);
|
||||
}
|
||||
else if (input[1] == '%')
|
||||
{
|
||||
input+=2;
|
||||
*output++='%';
|
||||
}
|
||||
else
|
||||
{
|
||||
error = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (error)
|
||||
{
|
||||
*output++ = *input++;
|
||||
}
|
||||
}
|
||||
|
||||
// benski> We have the luxury of knowing that decoding will ALWAYS produce smaller strings
|
||||
// so we can do it in-place
|
||||
void Query_Unescape(char *str)
|
||||
{
|
||||
const char *itr = str;
|
||||
while (*itr)
|
||||
{
|
||||
switch (*itr)
|
||||
{
|
||||
case '%':
|
||||
DecodeEscapedUTF8(str, itr);
|
||||
break;
|
||||
default:
|
||||
*str++ = *itr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
*str = 0;
|
||||
}
|
||||
|
30
Src/nde/android/Query.h
Normal file
30
Src/nde/android/Query.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#define TOKEN_UNKNOWN -1 // BLAAAAA!!!!!!!!
|
||||
#define TOKEN_EOQ 0 // End of Query
|
||||
#define TOKEN_IDENTIFIER 1 // Column name or data to match against
|
||||
#define TOKEN_EQUAL 2 // =, ==, IS
|
||||
#define TOKEN_NOTEQUAL 3 // !=, =!, <>, ><
|
||||
#define TOKEN_BELOW 4 // <
|
||||
#define TOKEN_ABOVE 5 // >
|
||||
#define TOKEN_BOREQUAL 6 // <=, =<
|
||||
#define TOKEN_AOREQUAL 7 // >=, =>
|
||||
#define TOKEN_NOT 8 // !, NOT
|
||||
#define TOKEN_AND 9 // &, &&, AND
|
||||
#define TOKEN_OR 10 // |, ||, OR
|
||||
#define TOKEN_PAROPEN 11 // (
|
||||
#define TOKEN_PARCLOSE 12 // )
|
||||
#define TOKEN_CONTAINS 13 // HAS
|
||||
#define TOKEN_BEGINS 14 // string starts with...
|
||||
#define TOKEN_ENDS 15 // string ends with...
|
||||
#define TOKEN_LIKE 16 // string is nearly (excluding "the " and whitespace etc)
|
||||
#define TOKEN_ISEMPTY 17 // field does not exists
|
||||
#define TOKEN_SQBRACKETOPEN 18 // [
|
||||
#define TOKEN_SQBRACKETCLOSE 19 // ]
|
||||
#define TOKEN_COMMA 20 // ,
|
||||
#define TOKEN_NOTCONTAINS 21 // NOTHAS
|
||||
#define TOKEN_ISNOTEMPTY 22 // field does not exists
|
||||
#define TOKEN_BEGINSLIKE 23 // string is nearly starts with (excluding "the " and whitespace etc)
|
||||
|
||||
// in-place
|
||||
void Query_Unescape(char *p);
|
124
Src/nde/android/Record.cpp
Normal file
124
Src/nde/android/Record.cpp
Normal file
|
@ -0,0 +1,124 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Record Class
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
//#include "record.h"
|
||||
#include "../nde.h"
|
||||
#include <stdio.h>
|
||||
|
||||
void RecordBase::Retain()
|
||||
{
|
||||
ref_count++;
|
||||
}
|
||||
|
||||
void RecordBase::Release()
|
||||
{
|
||||
if (--ref_count == 0)
|
||||
delete this;
|
||||
}
|
||||
|
||||
RecordBase::RecordBase()
|
||||
{
|
||||
ref_count = 1;
|
||||
InsertionPoint = 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Record::Record(int RecordPos, int insertionPoint, VFILE *TableHandle, Table *ParentTable)
|
||||
{
|
||||
InsertionPoint = insertionPoint;
|
||||
Record *columns = ParentTable->GetColumns();
|
||||
int max=columns ? columns->Fields.size() : 128;
|
||||
if (RecordPos != 0)
|
||||
{
|
||||
int n=0;
|
||||
uint32_t ThisPos = RecordPos;
|
||||
while (ThisPos)
|
||||
{
|
||||
if (n >= max)
|
||||
break;
|
||||
Vfseek(TableHandle, ThisPos, SEEK_SET);
|
||||
Field Entry (ThisPos);
|
||||
Field *TypedEntry = Entry.ReadField(ParentTable, ThisPos, &ThisPos);
|
||||
|
||||
if (!TypedEntry) break; // some db error?
|
||||
|
||||
AddField(TypedEntry);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
RecordBase::~RecordBase()
|
||||
{
|
||||
Fields.deleteAll();
|
||||
}
|
||||
|
||||
ColumnField *Record::GetColumnByName(const char *name)
|
||||
{
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
ColumnField *p = (ColumnField *)*itr;
|
||||
if (!strcasecmp(p->GetFieldName(), name))
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Record::WriteFields(Table *ParentTable, int RecordIndex)
|
||||
{
|
||||
Field *previous = 0;
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
Field *p = *itr;
|
||||
p->WriteField(ParentTable, previous, (Field *)p->next);
|
||||
previous = p;
|
||||
}
|
||||
return WriteIndex(ParentTable, RecordIndex);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Record::WriteIndex(Table *ParentTable, int RecordIndex)
|
||||
{
|
||||
int P=0;
|
||||
if (RecordIndex == NEW_RECORD)
|
||||
RecordIndex = ParentTable->index->Insert(InsertionPoint);
|
||||
if (!Fields.empty())
|
||||
{
|
||||
Field *f = *Fields.begin();
|
||||
P=f->GetFieldPos();
|
||||
}
|
||||
return ParentTable->index->Update(RecordIndex, P, this, FALSE);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Record::Delete(Table *ParentTable, int RecordIndex)
|
||||
{
|
||||
ParentTable->index->Delete(RecordIndex, ParentTable->index->Get(RecordIndex), this);
|
||||
}
|
||||
|
||||
void Record::WalkFields(FieldsWalker callback, void *context)
|
||||
{
|
||||
if (callback)
|
||||
{
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
if (!callback(this, *itr, context))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
1196
Src/nde/android/Scanner.cpp
Normal file
1196
Src/nde/android/Scanner.cpp
Normal file
File diff suppressed because it is too large
Load diff
148
Src/nde/android/Scanner.h
Normal file
148
Src/nde/android/Scanner.h
Normal file
|
@ -0,0 +1,148 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Scanner Class Prototypes
|
||||
|
||||
Android (linux) implementation
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __SCANNER_H
|
||||
#define __SCANNER_H
|
||||
|
||||
#include "../nde.h"
|
||||
#include "record.h"
|
||||
#include "../index.h"
|
||||
#include <nu/Vector.h>
|
||||
#include <nu/ValueSet.h>
|
||||
#include "../LinkedList.h"
|
||||
class Table;
|
||||
class Index;
|
||||
|
||||
class Scanner : public LinkedListEntry
|
||||
{
|
||||
public:
|
||||
Record *GetRecord(int Idx);
|
||||
Scanner(Table *parentTable);
|
||||
void IndexModified(void);
|
||||
Index *GetIndex() { return index; }
|
||||
Index *index; // TODO: make protected
|
||||
protected:
|
||||
|
||||
~Scanner();
|
||||
|
||||
Table *pTable;
|
||||
bool iModified;
|
||||
typedef Vector<StringField *> SearchStrings;
|
||||
SearchStrings search_strings;
|
||||
typedef ValueSet<unsigned char> SearchFields;
|
||||
SearchFields search_fields;
|
||||
bool search_any;
|
||||
|
||||
void GetCurrentRecord(void);
|
||||
bool MatchFilters(void);
|
||||
bool MatchSearches();
|
||||
bool MatchSearch(const SearchFields &fields, StringField *search_field);
|
||||
//BOOL MatchJoins(void);
|
||||
bool CheckFilters(void);
|
||||
void CacheLastLocate(int Id, int From, Field *field, Index *i, int j);
|
||||
|
||||
static int Query_LookupToken(const char *token);
|
||||
void Query_CleanUp(void);
|
||||
void Query_SyntaxError(int c);
|
||||
public:
|
||||
static int Query_GetNextToken(const char *p, int *size, char **token, int tokentable=0);
|
||||
static const char *Query_EatSpace(const char *p);
|
||||
static char *Query_ProbeSpace(char *p);
|
||||
static const char *Query_ProbeNonAlphaNum(const char *p);
|
||||
static char *Query_ProbeAlphaNum(char *p);
|
||||
static int Query_isControlChar(char p);
|
||||
|
||||
bool Query(const char *query);
|
||||
bool Query_Parse(const char *query);
|
||||
|
||||
const char *GetLastQuery();
|
||||
|
||||
public://fucko: protected
|
||||
LinkedList pstack;
|
||||
char *token;
|
||||
char *last_query;
|
||||
int last_query_failed;
|
||||
|
||||
protected:
|
||||
Record *CurrentRecord;
|
||||
int CurrentRecordIdx;
|
||||
LinkedList FilterList;
|
||||
Index *lastLocateIndex;
|
||||
int lastLocateIdx;
|
||||
Field *lastLocateFieldClone;
|
||||
int lastLocateFrom;
|
||||
int lastLocateId;
|
||||
bool Edition;
|
||||
int ResultPtr;
|
||||
bool FiltersOK;
|
||||
|
||||
public:
|
||||
bool MatchFilter(Filter *filter);
|
||||
typedef bool (*FilterWalker)(Scanner *scanner, Filter *filter, void *context);
|
||||
void WalkFilters(FilterWalker walker, void *context);
|
||||
|
||||
ColumnField *GetColumnByName(const char *FieldName);
|
||||
ColumnField *GetColumnById(unsigned char id);
|
||||
|
||||
Field *NewFieldByName(const char *fieldName, unsigned char Perm);
|
||||
Field *NewFieldById(unsigned char Id, unsigned char Perm);
|
||||
void DeleteField(Field *field);
|
||||
void DeleteFieldByName(const char *name);
|
||||
void DeleteFieldById(unsigned char Id);
|
||||
|
||||
void Cancel(void);
|
||||
void Insert(void);
|
||||
void Edit(void);
|
||||
void Post(void);
|
||||
void Delete(void);
|
||||
|
||||
Field *GetFieldByName(const char *FieldName);
|
||||
Field *GetFieldById(unsigned char Id);
|
||||
|
||||
void First(int *killswitch=0);
|
||||
void Last(int *killswitch=0);
|
||||
int Next(int *killswitch=0);
|
||||
int Previous(int *killswitch=0);
|
||||
bool Eof(void);
|
||||
bool Bof(void);
|
||||
void New(void);
|
||||
int GetRecordsCount(void);
|
||||
void GetRecordById(int Id, bool checkFilters=true);
|
||||
int GetRecordId(void);
|
||||
void Sync(void);
|
||||
bool LocateByName(const char *column, int From, Field *field, int *nskip=NULL);
|
||||
bool LocateById(int Id, int From, Field *field, int *nskip=NULL);
|
||||
bool LocateByIdEx(int Id, int From, Field *field, int *nskip, int comp_mode);
|
||||
|
||||
// Filters
|
||||
int AddFilterByName(const char *name, Field *Data, unsigned char Op);
|
||||
int AddFilterById(unsigned char Id, Field *Data, unsigned char Op);
|
||||
int AddFilterOp(unsigned char Op);
|
||||
void RemoveFilters(void);
|
||||
Filter *GetLastFilter(void);
|
||||
|
||||
bool SetWorkingIndexByName(const char *desc);
|
||||
bool SetWorkingIndexById(unsigned char Id);
|
||||
|
||||
void Search(const char *search_string);
|
||||
bool HasIndexChanged(void) { return iModified; }
|
||||
void ClearDirtyBit(void);
|
||||
float FragmentationLevel(void);
|
||||
|
||||
Table *GetTable();
|
||||
int in_query_parser;
|
||||
int disable_date_resolution;
|
||||
};
|
||||
|
||||
#endif
|
292
Src/nde/android/StringField.cpp
Normal file
292
Src/nde/android/StringField.cpp
Normal file
|
@ -0,0 +1,292 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
StringField Class
|
||||
Android (linux) specific version
|
||||
|
||||
Field data layout:
|
||||
[2 bytes] string length (bytes)
|
||||
[length bytes] String data. UTF-16 data will start with a BOM
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "../nde.h"
|
||||
#include "StringField.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
StringField::StringField(const char *Str, int strkind)
|
||||
{
|
||||
InitField();
|
||||
Type = FIELD_STRING;
|
||||
if (Str)
|
||||
{
|
||||
if (strkind == STRING_IS_WCHAR)
|
||||
String = ndestring_wcsdup(Str);
|
||||
else
|
||||
{
|
||||
String = const_cast<char *>(Str);
|
||||
ndestring_retain(String);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void StringField::InitField(void)
|
||||
{
|
||||
Type = FIELD_STRING;
|
||||
// String = NULL;
|
||||
String = NULL;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
StringField::StringField()
|
||||
{
|
||||
InitField();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
StringField::~StringField()
|
||||
{
|
||||
ndestring_release(String);
|
||||
String=0;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void StringField::ReadTypedData(const uint8_t *data, size_t len)
|
||||
{
|
||||
size_t pos=0;
|
||||
unsigned short c;
|
||||
|
||||
CHECK_SHORT(len);
|
||||
c = GET_SHORT();
|
||||
pos+=2;
|
||||
if (c)
|
||||
{
|
||||
bool unicode=false;
|
||||
bool utf16BE=false;
|
||||
if (c >= 2 // enough room for BOM
|
||||
&& (c & 1) == 0) // can't be unicode if it's not an even multiple of 2
|
||||
{
|
||||
uint16_t BOM=GET_SHORT();
|
||||
if (BOM == 0xFEFF)
|
||||
{
|
||||
pos+=2;
|
||||
c-=2;
|
||||
unicode=true;
|
||||
}
|
||||
else if (BOM == 0xFFFE)
|
||||
{
|
||||
pos+=2;
|
||||
c-=2;
|
||||
unicode=true;
|
||||
utf16BE=true;
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_BIN(len, c);
|
||||
if (unicode)
|
||||
{
|
||||
ndestring_release(String);
|
||||
if (utf16BE)
|
||||
{
|
||||
size_t bytes = utf16BE_to_utf8((uint16_t *)(data+pos), c>>1, 0, 0);
|
||||
String = ndestring_malloc(bytes+1);
|
||||
utf16BE_to_utf8((uint16_t *)(data+pos), c>>1, String, bytes);
|
||||
String[bytes]=0;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t bytes = utf16LE_to_utf8((uint16_t *)(data+pos), c>>1, 0, 0);
|
||||
String = ndestring_malloc(bytes+1);
|
||||
utf16LE_to_utf8((uint16_t *)(data+pos), c>>1, String, bytes);
|
||||
String[bytes]=0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// TODO: check for utf-8 byte marker
|
||||
String = ndestring_malloc(c+1);
|
||||
GET_BINARY((uint8_t *)String, data, c, pos);
|
||||
String[c]=0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void StringField::WriteTypedData(uint8_t *data, size_t len)
|
||||
{
|
||||
int pos=0;
|
||||
|
||||
if (String)
|
||||
{
|
||||
unsigned short c = (unsigned short)strlen(String);
|
||||
// write size
|
||||
CHECK_SHORT(len);
|
||||
PUT_SHORT(c); pos+=2;
|
||||
|
||||
// write string
|
||||
CHECK_BIN(len, c);
|
||||
PUT_BINARY(data, (uint8_t *)String, c, pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK_SHORT(len);
|
||||
PUT_SHORT(0); pos+=2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
char *StringField::GetString(void)
|
||||
{
|
||||
return String;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void StringField::SetString(const char *Str)
|
||||
{
|
||||
if (!Str) return;
|
||||
|
||||
ndestring_release(String);
|
||||
String = NULL;
|
||||
String = ndestring_wcsdup(Str);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void StringField::SetNDEString(char *Str)
|
||||
{
|
||||
if (!Str) return;
|
||||
|
||||
// copy and then release, just in case we're copying into ourselves
|
||||
char *oldStr = String;
|
||||
String = Str;
|
||||
ndestring_retain(String);
|
||||
ndestring_release(oldStr);
|
||||
}
|
||||
//---------------------------------------------------------------------------
|
||||
size_t StringField::GetDataSize(void)
|
||||
{
|
||||
if (String)
|
||||
{
|
||||
return strlen(String) + 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int StringField::Compare(Field *Entry)
|
||||
{
|
||||
if (!Entry) return -1;
|
||||
if (Entry->GetType() != GetType()) return 0;
|
||||
return mystricmp(GetString(), ((StringField*)Entry)->GetString());
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int StringField::Starts(Field *Entry)
|
||||
{
|
||||
if (!Entry) return -1;
|
||||
if (Entry->GetType() != GetType()) return 0;
|
||||
return (mystristr(GetString(), ((StringField*)Entry)->GetString()) == GetString());
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int StringField::Contains(Field *Entry)
|
||||
{
|
||||
if (!Entry) return -1;
|
||||
if (Entry->GetType() != GetType()) return 0;
|
||||
return (mystristr(GetString(), ((StringField*)Entry)->GetString()) != NULL);
|
||||
}
|
||||
|
||||
Field *StringField::Clone(Table *pTable)
|
||||
{
|
||||
StringField *clone = new StringField(String, STRING_IS_NDESTRING);
|
||||
clone->Pos = FIELD_CLONE;
|
||||
clone->ID = ID;
|
||||
clone->MaxSizeOnDisk = GetDataSize();
|
||||
return clone;
|
||||
}
|
||||
|
||||
bool StringField::ApplyFilter(Field *Data, int op)
|
||||
{
|
||||
// TODO: maybe do this?
|
||||
|
||||
if (op == FILTER_ISEMPTY || op == FILTER_ISNOTEMPTY)
|
||||
{
|
||||
bool r = (op == FILTER_ISEMPTY);
|
||||
if (!String)
|
||||
return r;
|
||||
|
||||
if (String && String[0] == 0)
|
||||
return r;
|
||||
|
||||
return !r;
|
||||
}
|
||||
//
|
||||
bool r;
|
||||
StringField *compField = (StringField *)Data;
|
||||
|
||||
const char *p = compField->GetString();
|
||||
const char *d = GetString();
|
||||
if (!p)
|
||||
p = "";
|
||||
if (!d)
|
||||
d = "";
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case FILTER_EQUALS:
|
||||
r = !nde_stricmp(d, p);
|
||||
break;
|
||||
case FILTER_NOTEQUALS:
|
||||
r = !!nde_stricmp(d, p);
|
||||
break;
|
||||
case FILTER_CONTAINS:
|
||||
r = (NULL != stristr_ignore(d, p));
|
||||
break;
|
||||
case FILTER_NOTCONTAINS:
|
||||
r = (NULL == stristr_ignore(d, p));
|
||||
break;
|
||||
case FILTER_ABOVE:
|
||||
r = (bool)(nde_stricmp(d, p) > 0);
|
||||
break;
|
||||
case FILTER_ABOVEOREQUAL:
|
||||
r = (bool)(nde_stricmp(d, p) >= 0);
|
||||
break;
|
||||
case FILTER_BELOW:
|
||||
r = (bool)(nde_stricmp(d, p) < 0);
|
||||
break;
|
||||
case FILTER_BELOWOREQUAL:
|
||||
r = (bool)(nde_stricmp(d, p) <= 0);
|
||||
break;
|
||||
case FILTER_BEGINS:
|
||||
r = (bool)(nde_strnicmp(d, p, strlen(p)) == 0);
|
||||
break;
|
||||
case FILTER_ENDS:
|
||||
{
|
||||
size_t lenp = strlen(p), lend = strlen(d);
|
||||
if (lend < lenp) return 0; // too short
|
||||
r = (bool)(nde_stricmp((d + lend) - lenp, p) == 0);
|
||||
}
|
||||
break;
|
||||
case FILTER_LIKE:
|
||||
r = (bool)(nde_stricmp(d, p) == 0);
|
||||
break;
|
||||
case FILTER_BEGINSLIKE:
|
||||
r = (bool)(nde_strnicmp_ignore(d, p, strlen(p)) == 0);
|
||||
break;
|
||||
default:
|
||||
r = true;
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
50
Src/nde/android/StringField.h
Normal file
50
Src/nde/android/StringField.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
StringField Class Prototypes
|
||||
|
||||
Android (linux) implementation
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef __STRINGFIELD_H
|
||||
#define __STRINGFIELD_H
|
||||
#include "../NDEString.h"
|
||||
|
||||
class StringField : public Field
|
||||
{
|
||||
public:
|
||||
StringField();
|
||||
~StringField();
|
||||
|
||||
|
||||
StringField(const char *Str, int strkind=STRING_IS_WCHAR);
|
||||
char *GetString(void);
|
||||
void SetString(const char *Str);
|
||||
void SetNDEString(char *Str);
|
||||
|
||||
protected:
|
||||
virtual void ReadTypedData(const uint8_t *, size_t len);
|
||||
virtual void WriteTypedData(uint8_t *, size_t len);
|
||||
virtual size_t GetDataSize(void);
|
||||
virtual int Compare(Field *Entry);
|
||||
virtual int Starts(Field *Entry);
|
||||
virtual int Contains(Field *Entry);
|
||||
|
||||
virtual bool ApplyFilter(Field *Data, int op);
|
||||
virtual Field *Clone(Table *pTable);
|
||||
void InitField(void);
|
||||
|
||||
char *String;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
846
Src/nde/android/Table.cpp
Normal file
846
Src/nde/android/Table.cpp
Normal file
|
@ -0,0 +1,846 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Table Class
|
||||
|
||||
Android (linux) implementation
|
||||
--------------------------------------------------------------------------- */
|
||||
#include "Table.h"
|
||||
#include "../nde.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../CRC.H"
|
||||
#include "../NDEString.h"
|
||||
#include "IndexField.h"
|
||||
#include "ColumnField.h"
|
||||
#include "../DBUtils.h"
|
||||
const char *tSign="NDETABLE";
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Table::Table(const char *TableName, const char *Idx, int Create, Database *_db, int _Cached)
|
||||
: Scanner(this), use_row_cache(false), columns_cached(false)
|
||||
{
|
||||
Handle = 0;
|
||||
memset(column_ids, FIELD_UNKNOWN, 255);
|
||||
Cached = _Cached;
|
||||
db = _db;
|
||||
AutoCreate = Create;
|
||||
Name = ndestring_wcsdup(TableName);
|
||||
IdxName = ndestring_wcsdup(Idx);
|
||||
Init();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::Init()
|
||||
{
|
||||
numErrors = 0;
|
||||
Scanners = new LinkedList();
|
||||
// benski> cut: Handle=NULL;
|
||||
IdxHandle=NULL;
|
||||
FieldsRecord=NULL;
|
||||
IndexList=NULL;
|
||||
GLocateUpToDate = FALSE;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Table::~Table()
|
||||
{
|
||||
Reset();
|
||||
if (Handle) // Reset doesn't completely destroy Handle
|
||||
Vfdestroy(Handle);
|
||||
Handle = 0;
|
||||
|
||||
ndestring_release(Name);
|
||||
ndestring_release(IdxName);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::Reset()
|
||||
{
|
||||
if (IndexList) IndexList->Release();
|
||||
IndexList=0;
|
||||
if (FieldsRecord) FieldsRecord->Release();
|
||||
FieldsRecord=0;
|
||||
delete Scanners;
|
||||
Scanners=0;
|
||||
if (Handle)
|
||||
Vfclose(Handle); // close (but don't destroy) to keep mutex open.
|
||||
if (IdxHandle)
|
||||
Vfdestroy(IdxHandle);
|
||||
IdxHandle = 0;
|
||||
|
||||
for (RowCache::iterator itr=rowCache.begin();itr!=rowCache.end();itr++)
|
||||
{
|
||||
if (itr->second)
|
||||
itr->second->Release();
|
||||
}
|
||||
rowCache.clear();
|
||||
|
||||
memset(column_ids, FIELD_UNKNOWN, 255);
|
||||
columns_cached=false;
|
||||
}
|
||||
|
||||
|
||||
struct IndexNewWalkerContext
|
||||
{
|
||||
IndexNewWalkerContext(Table *_table)
|
||||
{
|
||||
N = -1;
|
||||
table = _table;
|
||||
}
|
||||
int N;
|
||||
Table *table;
|
||||
};
|
||||
|
||||
bool Table::IndexNewWalker(IndexRecord *record, Field *entry, void *context_in)
|
||||
{
|
||||
IndexNewWalkerContext *context = (IndexNewWalkerContext *)context_in;
|
||||
IndexField *p = (IndexField *)entry;
|
||||
p->index = new Index(context->table->IdxHandle, p->ID, context->N++, p->Type, FALSE, 0, context->table);
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
bool Table::Open()
|
||||
{
|
||||
bool Valid;
|
||||
int justcreated = 0;
|
||||
|
||||
if (!Handle)
|
||||
Handle = Vfnew(Name, "r+b", Cached);
|
||||
if (!Handle) return FALSE;
|
||||
if (!Vflock(Handle))
|
||||
{
|
||||
Vfdestroy(Handle);
|
||||
Handle = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Handle = Vfopen(Handle, Name, "r+b", Cached);
|
||||
IdxHandle = Vfopen(0, IdxName, "r+b", 1);
|
||||
Valid = (Handle && IdxHandle);
|
||||
|
||||
// unlock
|
||||
if (Valid || !AutoCreate)
|
||||
{
|
||||
//if (Handle)
|
||||
//Vfunlock(Handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Handle)
|
||||
{
|
||||
Vfclose(Handle);
|
||||
if (IdxHandle)
|
||||
Vfdestroy(IdxHandle);
|
||||
IdxHandle = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IdxHandle)
|
||||
Vfdestroy(IdxHandle);
|
||||
IdxHandle = 0;
|
||||
Handle = Vfnew(Name, "w+b", Cached);
|
||||
if (!Vflock(Handle))
|
||||
{
|
||||
Vfdestroy(Handle);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
Handle = Vfopen(Handle, Name, "w+b", Cached);
|
||||
IdxHandle = Vfopen(0, IdxName, "w+b", 1);
|
||||
Valid = (Handle && IdxHandle);
|
||||
|
||||
if (Valid)
|
||||
{
|
||||
Vfwrite(__TABLE_SIGNATURE__, strlen(__TABLE_SIGNATURE__), Handle);
|
||||
Vfwrite(__INDEX_SIGNATURE__, strlen(__TABLE_SIGNATURE__), IdxHandle);
|
||||
// TODO bensk> change if NUM_SPECIAL_RECORDS ever increases
|
||||
int v=NUM_SPECIAL_RECORDS;//strlen(__TABLE_SIGNATURE__);
|
||||
Vfwrite(&v, sizeof(v), IdxHandle);
|
||||
// v = 0; fwrite(&v, sizeof(v), 1, IdxHandle);
|
||||
v = -1; Vfwrite(&v, sizeof(v), IdxHandle); // write ID
|
||||
v = 0;
|
||||
for (int i=0;i<NUM_SPECIAL_RECORDS;i++)
|
||||
{
|
||||
Vfwrite(&v, sizeof(v), IdxHandle);
|
||||
Vfwrite(&v, sizeof(v), IdxHandle);
|
||||
}
|
||||
Sync();
|
||||
justcreated = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!Valid)
|
||||
{
|
||||
if (Handle) Vfdestroy(Handle);
|
||||
if (IdxHandle) Vfdestroy(IdxHandle);
|
||||
Handle = NULL;
|
||||
IdxHandle = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
int Ptr;
|
||||
|
||||
char test1[9]={0,};
|
||||
char test2[9]={0,};
|
||||
|
||||
Vfseek(Handle, 0, SEEK_SET);
|
||||
Vfread(test1, strlen(__TABLE_SIGNATURE__), Handle);
|
||||
Vfseek(IdxHandle, 0, SEEK_SET);
|
||||
Vfread(test2, strlen(__INDEX_SIGNATURE__), IdxHandle);
|
||||
test1[8]=0;
|
||||
test2[8]=0;
|
||||
if (strcmp(test1, __TABLE_SIGNATURE__) || strcmp(test2, __INDEX_SIGNATURE__))
|
||||
{
|
||||
if (Handle) Vfdestroy(Handle);
|
||||
Handle = 0;
|
||||
if (IdxHandle) Vfdestroy(IdxHandle);
|
||||
IdxHandle = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Load default index
|
||||
IndexField *field;
|
||||
field = new IndexField(PRIMARY_INDEX, -1, -1, "None");
|
||||
field->index = new Index(IdxHandle, PRIMARY_INDEX, -1, -1, FALSE, 0, this);
|
||||
|
||||
// Get indexes
|
||||
Ptr = field->index->Get(INDEX_RECORD_NUM);
|
||||
IndexList = new IndexRecord(Ptr, INDEX_RECORD_NUM, Handle, this);
|
||||
if (!IndexList)
|
||||
{
|
||||
delete field;
|
||||
if (Handle) Vfdestroy(Handle);
|
||||
Handle = 0;
|
||||
if (IdxHandle) Vfdestroy(IdxHandle);
|
||||
IdxHandle = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Init them
|
||||
IndexNewWalkerContext newContext(this);
|
||||
IndexList->WalkFields(IndexNewWalker, &newContext);
|
||||
|
||||
// Add default in case its not there (if it is it won't be added by addfield)
|
||||
IndexList->AddField(field);
|
||||
|
||||
// Get the default index (whether loaded or preloaded)
|
||||
Scanner::index = ((IndexField*)IndexList->GetField(PRIMARY_INDEX))->index;
|
||||
|
||||
// If it's different from preloaded, delete preloaded
|
||||
if (field->index != Scanner::index)
|
||||
{
|
||||
delete field;
|
||||
field=0;
|
||||
}
|
||||
|
||||
// Set up colaboration
|
||||
IndexList->BuildCollaboration();
|
||||
|
||||
// Get columns
|
||||
Ptr = Scanner::index->Get(FIELDS_RECORD_NUM);
|
||||
FieldsRecord = new Record(Ptr, FIELDS_RECORD_NUM, Handle, this);
|
||||
if (!FieldsRecord)
|
||||
{
|
||||
IndexList->Release();
|
||||
IndexList=0;
|
||||
if (Handle) Vfdestroy(Handle);
|
||||
Handle = 0;
|
||||
if (IdxHandle) Vfdestroy(IdxHandle);
|
||||
IdxHandle = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// update the column cache
|
||||
FieldsRecord->WalkFields(BuildColumnCache, this);
|
||||
columns_cached=true;
|
||||
}
|
||||
|
||||
|
||||
#if 0 // TODO
|
||||
if (Valid && !justcreated)
|
||||
{
|
||||
if (IndexList->NeedFix())
|
||||
Compact();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (Valid) First();
|
||||
if (Handle)
|
||||
Vfunlock(Handle);
|
||||
return Valid;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::Close(void)
|
||||
{
|
||||
int v=0;
|
||||
|
||||
if (Handle && IndexList && Vflock(Handle, 0))
|
||||
{
|
||||
IndexList->WalkFields(IndexWriteWalker, 0);
|
||||
}
|
||||
|
||||
delete Scanners;
|
||||
Scanners = NULL;
|
||||
|
||||
Vsync(Handle);
|
||||
if (IdxHandle)
|
||||
{
|
||||
Vfdestroy(IdxHandle);
|
||||
IdxHandle = NULL;
|
||||
v |= 2;
|
||||
}
|
||||
if (Handle)
|
||||
{
|
||||
Vfdestroy(Handle);
|
||||
Handle = NULL;
|
||||
v |= 1;
|
||||
}
|
||||
|
||||
if (v != 3)
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
bool Table::IndexWriteWalker(IndexRecord *record, Field *entry, void *context)
|
||||
{
|
||||
IndexField *field = (IndexField *)entry;
|
||||
field->index->WriteIndex();
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::Sync(void)
|
||||
{
|
||||
if (!Vflock(Handle))
|
||||
return;
|
||||
|
||||
if (IndexList)
|
||||
IndexList->WalkFields(IndexWriteWalker, 0);
|
||||
|
||||
int err=0;
|
||||
if (!err && Handle) err|=Vsync(Handle);
|
||||
if (!err && IdxHandle) err|=Vsync(IdxHandle);
|
||||
|
||||
Vfunlock(Handle);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
ColumnField *Table::NewColumn(unsigned char FieldID, const char *FieldName, unsigned char FieldType, bool indexUnique)
|
||||
{
|
||||
columns_cached=false; // if they start writing new columns, kill the columns cache until they PostColumns()
|
||||
ColumnField *f = GetColumnById(FieldID);
|
||||
if (f) {
|
||||
int t = f->GetDataType();
|
||||
if (t != FieldType) {
|
||||
if (CompatibleFields(t, FieldType))
|
||||
{
|
||||
f->SetDataType(FieldType);
|
||||
goto aok;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
aok:
|
||||
if (GetColumnByName(FieldName))
|
||||
return NULL;
|
||||
ColumnField *field = new ColumnField(FieldID, FieldName, FieldType, this);
|
||||
column_ids[FieldID]=FieldType;
|
||||
FieldsRecord->AddField(field);
|
||||
return field;
|
||||
}
|
||||
|
||||
void Table::SetFieldSearchableById(unsigned char field_id, bool searchable)
|
||||
{
|
||||
ColumnField *column = GetColumnById(field_id);
|
||||
if (column)
|
||||
column->SetSearchable(searchable);
|
||||
if (searchable)
|
||||
{
|
||||
search_fields.insert(field_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
search_fields.erase(field_id);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
bool Table::BuildColumnCache(Record *record, Field *entry, void *context)
|
||||
{
|
||||
Table *table = (Table *)context;
|
||||
ColumnField *column = (ColumnField *)entry;
|
||||
unsigned char field_id=column->GetFieldId();
|
||||
table->column_ids[field_id] = column->GetDataType();
|
||||
|
||||
if (column->IsSearchableField())
|
||||
{
|
||||
table->search_fields.insert(field_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
table->search_fields.erase(field_id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::PostColumns(void)
|
||||
{
|
||||
FieldsRecord->WriteFields(this, FIELDS_RECORD_NUM);
|
||||
memset(column_ids, FIELD_UNKNOWN, 255);
|
||||
FieldsRecord->WalkFields(BuildColumnCache, this);
|
||||
columns_cached=true;
|
||||
}
|
||||
|
||||
unsigned char Table::GetColumnType(unsigned char Id)
|
||||
{
|
||||
if (columns_cached)
|
||||
{
|
||||
return column_ids[Id];
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetColumnById(Id)->GetDataType();
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
IndexField *Table::GetIndexByName(const char *name)
|
||||
{
|
||||
if (!IndexList)
|
||||
return NULL;
|
||||
return IndexList->GetIndexByName(name);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
IndexField *Table::GetIndexById(unsigned char Id)
|
||||
{
|
||||
if (!IndexList)
|
||||
return NULL;
|
||||
return (IndexField *)IndexList->GetField(Id);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::AddIndexByName(const char *name, const char *desc)
|
||||
{
|
||||
ColumnField *header = GetColumnByName(name);
|
||||
if (header)
|
||||
{
|
||||
unsigned char Idx = header->ID;
|
||||
AddIndexById(Idx, desc);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::AddIndexById(unsigned char Id, const char *desc)
|
||||
{
|
||||
if (GetIndexById(Id)) return;
|
||||
ColumnField *col = GetColumnById(Id);
|
||||
if (!col)
|
||||
return;
|
||||
IndexField *newindex = new IndexField(Id, IndexList->GetColumnCount(), col->GetDataType(), desc);
|
||||
newindex->index = new Index(IdxHandle, Id, IndexList->GetColumnCount(), col->GetDataType(), true, Scanner::index->NEntries, this);
|
||||
IndexList->AddField(newindex);
|
||||
|
||||
IndexField *previous = (IndexField *)newindex->prev;
|
||||
previous->index->Colaborate(newindex);
|
||||
IndexField *primary_index = (IndexField *)IndexList->GetField(PRIMARY_INDEX);
|
||||
newindex->index->Colaborate(primary_index);
|
||||
|
||||
previous->index->Propagate();
|
||||
|
||||
IndexList->WriteFields(this);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
bool Table::CheckIndexing(void)
|
||||
{
|
||||
if (IndexList->GetColumnCount() == 0) return true;
|
||||
|
||||
for (int i=0;i<Scanner::index->NEntries;i++)
|
||||
{
|
||||
if (!IndexList->CheckIndexing(i))
|
||||
return FALSE;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
struct IndexWalkerThunkContext
|
||||
{
|
||||
void *context;
|
||||
Table *_this;
|
||||
Table::IndexWalker callback;
|
||||
};
|
||||
|
||||
bool Table::IndexWalkerThunk(IndexRecord *record, Field *entry, void *context_in)
|
||||
{
|
||||
IndexWalkerThunkContext *context = (IndexWalkerThunkContext *)context_in;
|
||||
return context->callback(context->_this, (IndexField *)entry, context->context);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::WalkIndices(IndexWalker callback, void *context)
|
||||
{
|
||||
if (IndexList && callback)
|
||||
{
|
||||
IndexWalkerThunkContext walkerContext = { context, this, callback };
|
||||
IndexList->WalkFields(IndexWalkerThunk, &walkerContext);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::DropIndex(IndexField *Ptr)
|
||||
{
|
||||
if (!Ptr || Ptr->Type != FIELD_INDEX) return;
|
||||
if (Scanner::index == Ptr->index)
|
||||
{
|
||||
Scanner::index = ((IndexField*)IndexList->GetField(PRIMARY_INDEX))->index;
|
||||
|
||||
IndexList->BuildCollaboration();
|
||||
}
|
||||
IndexList->RemoveField(Ptr);
|
||||
if (Scanner::index->SecIndex == Ptr)
|
||||
Scanner::index->SecIndex = 0;
|
||||
IndexList->WriteFields(this);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::DropIndexByName(const char *desc)
|
||||
{
|
||||
IndexField *indx = GetIndexByName(desc);
|
||||
if (!strcasecmp(desc, "None")) return;
|
||||
|
||||
if (indx)
|
||||
DropIndex(indx);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::DropIndexById(unsigned char Id)
|
||||
{
|
||||
if (!IndexList)
|
||||
return;
|
||||
if (Id == (unsigned char)PRIMARY_INDEX) return;
|
||||
IndexField *indx=(IndexField *)IndexList->GetField(Id);
|
||||
if (indx)
|
||||
DropIndex(indx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
bool Table::LocateByIdEx(int Id, int From, Field *field, int comp_mode)
|
||||
{
|
||||
return Scanner::LocateByIdEx(Id, From, field, NULL, comp_mode);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Record *Table::GetColumns(void)
|
||||
{
|
||||
if (!FieldsRecord)
|
||||
return NULL;
|
||||
return FieldsRecord;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Scanner *Table::NewScanner()
|
||||
{
|
||||
Scanner *s = new Scanner(this);
|
||||
/*if (Scanners->GetNElements() > 0)*/
|
||||
s->index = Scanner::index;
|
||||
Scanners->AddEntry(s, true);
|
||||
return s;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Scanner *Table::GetDefaultScanner()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::DeleteScanner(Scanner *scan)
|
||||
{
|
||||
if (!scan) return;
|
||||
Scanners->RemoveEntry(scan);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::IndexModified(void)
|
||||
{
|
||||
Scanner *s = (Scanner *)Scanners->GetHead();
|
||||
while (s)
|
||||
{
|
||||
s->IndexModified();
|
||||
s = (Scanner *)s->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::SetGlobalLocateUpToDate(bool is) {
|
||||
GLocateUpToDate = is;
|
||||
}
|
||||
|
||||
struct ColumnWalkContext
|
||||
{
|
||||
Table *ctable;
|
||||
};
|
||||
|
||||
bool Table::Compact_ColumnWalk(Record *record, Field *entry, void *context_in)
|
||||
{
|
||||
ColumnField *field = static_cast<ColumnField *>(entry);
|
||||
ColumnWalkContext *context = (ColumnWalkContext *)context_in;
|
||||
Table *ctable = context->ctable;
|
||||
|
||||
ctable->NewColumn(field->GetFieldId(), field->GetFieldName(), field->GetDataType(), FALSE);
|
||||
return true;
|
||||
}
|
||||
|
||||
struct ColumnWalk2Context
|
||||
{
|
||||
Table *ctable;
|
||||
Table *thisTable;
|
||||
uint8_t *data;
|
||||
size_t data_size;
|
||||
int gotstuff;
|
||||
};
|
||||
|
||||
bool Table::Compact_ColumnWalk2(Record *record, Field *entry, void *context_in)
|
||||
{
|
||||
ColumnField *colfield = (ColumnField *)entry;
|
||||
ColumnWalk2Context *context = (ColumnWalk2Context *)context_in;
|
||||
|
||||
unsigned char fieldid = colfield->GetFieldId();
|
||||
//char *fieldname = colfield->GetFieldName();
|
||||
Field *mfield = context->thisTable->GetFieldById(fieldid);
|
||||
//Field *mfield = GetFieldByName(fieldname);
|
||||
if (mfield != NULL) {
|
||||
if (!context->gotstuff) {
|
||||
context->ctable->New();
|
||||
context->gotstuff = 1;
|
||||
}
|
||||
Field *cfield = context->ctable->NewFieldById(fieldid, 0);
|
||||
//Field *cfield = ctable->NewFieldByName(fieldname, mfield->GetPerm());
|
||||
size_t len = mfield->GetDataSize();
|
||||
if (len > context->data_size)
|
||||
{
|
||||
context->data_size = len;
|
||||
context->data = (uint8_t *)realloc(context->data, context->data_size);
|
||||
}
|
||||
mfield->WriteTypedData(context->data, len);
|
||||
cfield->ReadTypedData(context->data, len);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Table::Compact_IndexWalk(Table *table, IndexField *field, void *context)
|
||||
{
|
||||
Table *ctable = (Table *)context;
|
||||
|
||||
if (strcasecmp(field->GetIndexName(), "None"))
|
||||
ctable->AddIndexById(field->GetFieldId(), field->GetIndexName());
|
||||
return true;
|
||||
}
|
||||
#if 0 // TODO
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::Compact(int *progress) {
|
||||
// ok so we're gonna be cheating a bit, instead of figuring out how to safely modify all those
|
||||
// nifty indexes that cross reference themselves and blablabla, we're just gonna duplicate the
|
||||
// whole table from scratch, overwrite ourselves, and reopen the table. duh.
|
||||
|
||||
if (!Vflock(Handle))
|
||||
{
|
||||
if (progress != NULL) *progress = 100;
|
||||
return;
|
||||
}
|
||||
// create a temporary table in windows temp dir
|
||||
wchar_t temp_table[MAX_PATH+12];
|
||||
wchar_t temp_index[MAX_PATH+12];
|
||||
wchar_t old_table[MAX_PATH+12];
|
||||
wchar_t old_index[MAX_PATH+12];
|
||||
DWORD pid=GetCurrentProcessId();
|
||||
|
||||
StringCbPrintfW(temp_table, sizeof(temp_table), L"%s.new%08X", Name,pid);
|
||||
StringCbPrintfW(temp_index, sizeof(temp_index),L"%s.new%08X", IdxName,pid);
|
||||
StringCbPrintfW(old_table, sizeof(old_table),L"%s.old%08X", Name,pid);
|
||||
StringCbPrintfW(old_index, sizeof(old_index),L"%s.old%08X", IdxName,pid);
|
||||
|
||||
// delete them, in case we crashed while packing
|
||||
|
||||
DeleteFileW(temp_table);
|
||||
DeleteFileW(temp_index);
|
||||
DeleteFileW(old_table);
|
||||
DeleteFileW(old_index);
|
||||
|
||||
// create a brand new db and a brand new table
|
||||
Table *ctable = db->OpenTable(temp_table, temp_index, NDE_OPEN_ALWAYS, Cached);
|
||||
|
||||
// duplicate the columns
|
||||
Record *record = GetColumns();
|
||||
if (record != NULL)
|
||||
{
|
||||
ColumnWalkContext context;
|
||||
context.ctable = ctable;
|
||||
record->WalkFields(Compact_ColumnWalk, &context);
|
||||
}
|
||||
ctable->PostColumns();
|
||||
|
||||
// duplicate the indexes
|
||||
WalkIndices(Compact_IndexWalk, (void *)ctable);
|
||||
|
||||
// duplicate the data
|
||||
int reccount = GetRecordsCount();
|
||||
|
||||
int count = 0;
|
||||
First();
|
||||
ColumnWalk2Context context;
|
||||
context.data_size = 65536;
|
||||
context.data = (uint8_t *)malloc(65536);
|
||||
context.ctable = ctable;
|
||||
context.thisTable = this;
|
||||
|
||||
while (1) {
|
||||
int lasterr = NumErrors();
|
||||
GetDefaultScanner()->GetRecordById(count, FALSE);
|
||||
count++;
|
||||
|
||||
if (Eof() || count > reccount) break;
|
||||
|
||||
if (NumErrors() > lasterr)
|
||||
continue;
|
||||
|
||||
Index *idx = GetDefaultScanner()->GetIndex();
|
||||
int pos = idx->Get(GetDefaultScanner()->GetRecordId());
|
||||
|
||||
if (pos == 0) continue;
|
||||
|
||||
int pr = (int)((float)GetRecordId()/(float)reccount*100.0f);
|
||||
if (progress != NULL) *progress = pr;
|
||||
context.gotstuff = 0;
|
||||
|
||||
if (record != NULL)
|
||||
record->WalkFields(Compact_ColumnWalk2, &context);
|
||||
|
||||
if (context.gotstuff)
|
||||
ctable->Post();
|
||||
}
|
||||
free(context.data);
|
||||
|
||||
// done creating temp table
|
||||
db->CloseTable(ctable);
|
||||
|
||||
// reset the data structures and close underlying file handles
|
||||
Reset();
|
||||
|
||||
if (MoveFileW(Name,old_table))
|
||||
{
|
||||
if (MoveFileW(IdxName,old_index))
|
||||
{
|
||||
if (!MoveFileW(temp_table,Name) || !MoveFileW(temp_index,IdxName))
|
||||
{
|
||||
// failed, try to copy back
|
||||
DeleteFileW(Name);
|
||||
DeleteFileW(IdxName);
|
||||
MoveFileW(old_table,Name); // restore old file
|
||||
MoveFileW(old_index,IdxName); // restore old file
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MoveFileW(old_table,Name); // restore old file
|
||||
}
|
||||
}
|
||||
|
||||
// clean up our temp files
|
||||
DeleteFileW(temp_table);
|
||||
DeleteFileW(temp_index);
|
||||
DeleteFileW(old_table);
|
||||
DeleteFileW(old_index);
|
||||
|
||||
if (progress != NULL) *progress = 100;
|
||||
|
||||
// reopen our table
|
||||
Init();
|
||||
Open();
|
||||
}
|
||||
#endif
|
||||
ColumnField *Table::GetColumnById(unsigned char Idx)
|
||||
{
|
||||
if (!FieldsRecord)
|
||||
return NULL;
|
||||
return (ColumnField *)FieldsRecord->GetField(Idx);
|
||||
}
|
||||
|
||||
ColumnField *Table::GetColumnByName(const char *FieldName)
|
||||
{
|
||||
return FieldsRecord->GetColumnByName(FieldName);
|
||||
}
|
||||
|
||||
void Table::RowCache_Delete(int position)
|
||||
{
|
||||
if (use_row_cache)
|
||||
{
|
||||
RowCache::iterator found = rowCache.find(position);
|
||||
if (found != rowCache.end())
|
||||
{
|
||||
if (found->second)
|
||||
found->second->Release();
|
||||
rowCache.erase(found);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Table::RowCache_Remove(int position)
|
||||
{
|
||||
if (use_row_cache)
|
||||
{
|
||||
|
||||
Record *&row = rowCache[position];
|
||||
if (row)
|
||||
{
|
||||
row->Release();
|
||||
}
|
||||
|
||||
row = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Table::RowCache_Add(Record *record, int position)
|
||||
{
|
||||
if (use_row_cache)
|
||||
{
|
||||
record->Retain();
|
||||
|
||||
Record *&row = rowCache[position];
|
||||
if (row)
|
||||
{
|
||||
row->Release();
|
||||
}
|
||||
|
||||
row = record;
|
||||
}
|
||||
}
|
||||
|
||||
Record *Table::RowCache_Get(int position)
|
||||
{
|
||||
if (!use_row_cache)
|
||||
return 0;
|
||||
Record *row = rowCache[position];
|
||||
if (row)
|
||||
row->Retain();
|
||||
return row;
|
||||
}
|
||||
|
||||
void Table::EnableRowCache()
|
||||
{
|
||||
use_row_cache=true;
|
||||
}
|
166
Src/nde/android/Table.h
Normal file
166
Src/nde/android/Table.h
Normal file
|
@ -0,0 +1,166 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Table Class Prototypes
|
||||
Android (linux) implementation
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __TABLE_H
|
||||
#define __TABLE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "Scanner.h"
|
||||
#include <map>
|
||||
#include "IndexRecord.h"
|
||||
|
||||
class Table : private Scanner
|
||||
{
|
||||
public:
|
||||
// TODO: move these back to protected
|
||||
VFILE *Handle;
|
||||
using Scanner::index;
|
||||
bool use_row_cache;
|
||||
bool GLocateUpToDate;
|
||||
private:
|
||||
void Init();
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
LinkedList *Scanners;
|
||||
|
||||
protected:
|
||||
char *Name;
|
||||
char *IdxName;
|
||||
|
||||
VFILE *IdxHandle;
|
||||
int AutoCreate;
|
||||
Record *FieldsRecord;
|
||||
IndexRecord *IndexList;
|
||||
Database *db;
|
||||
int Cached;
|
||||
int numErrors;
|
||||
using Scanner::Edition;
|
||||
bool columns_cached;
|
||||
unsigned char column_ids[256];
|
||||
typedef std::map<int, Record*> RowCache;
|
||||
RowCache rowCache;
|
||||
|
||||
// Tables
|
||||
static bool Compact_ColumnWalk(Record *record, Field *entry, void *context_in);
|
||||
static bool Compact_ColumnWalk2(Record *record, Field *entry, void *context_in);
|
||||
static bool Compact_IndexWalk(Table *table, IndexField *entry, void *context);
|
||||
static bool IndexWriteWalker(IndexRecord *record, Field *entry, void *context);
|
||||
static bool IndexWalkerThunk(IndexRecord *record, Field *entry, void *context);
|
||||
static bool IndexNewWalker(IndexRecord *record, Field *entry, void *context);
|
||||
static bool BuildColumnCache(Record *record, Field *entry, void *context);
|
||||
public:
|
||||
typedef bool (*IndexWalker)(Table *table, IndexField *entry, void *context);
|
||||
Table(const char *TableName, const char *IdxName, int Create, Database *db, int Cached);
|
||||
~Table();
|
||||
bool Open();
|
||||
void Close();
|
||||
|
||||
// Columns
|
||||
ColumnField *NewColumn(unsigned char Id, const char *name, unsigned char type, bool indexUniques);
|
||||
|
||||
void DeleteColumn(ColumnField *field); // todo
|
||||
void DeleteColumnByName(const char *name); // todo
|
||||
void DeleteColumnById(unsigned char Id); // todo
|
||||
void PostColumns(void);
|
||||
NDE_API Record *GetColumns(void);
|
||||
ColumnField *GetColumnByName(const char *FieldName);
|
||||
ColumnField *GetColumnById(unsigned char Idx);
|
||||
unsigned char GetColumnType(unsigned char Id);
|
||||
|
||||
// Fields
|
||||
using Scanner::NewFieldByName;
|
||||
using Scanner::NewFieldById;
|
||||
using Scanner::GetFieldByName;
|
||||
using Scanner::GetFieldById;
|
||||
using Scanner::DeleteField;
|
||||
using Scanner::DeleteFieldByName;
|
||||
using Scanner::DeleteFieldById;
|
||||
|
||||
// Records
|
||||
using Scanner::First;
|
||||
using Scanner::Last;
|
||||
using Scanner::Next;
|
||||
using Scanner::Previous;
|
||||
using Scanner::Eof;
|
||||
using Scanner::Bof;
|
||||
using Scanner::New;
|
||||
using Scanner::Insert;
|
||||
using Scanner::Edit;
|
||||
using Scanner::Cancel;
|
||||
using Scanner::Post;
|
||||
using Scanner::Delete;
|
||||
using Scanner::GetRecordsCount;
|
||||
using Scanner::GetRecordById;
|
||||
using Scanner::GetRecordId;
|
||||
void Sync(void);
|
||||
using Scanner::LocateByName;
|
||||
using Scanner::LocateById;
|
||||
bool LocateByIdEx(int Id, int From, Field *field, int comp_mode);
|
||||
|
||||
// Indexes
|
||||
void AddIndexByName(const char *FieldName, const char *KeyName);
|
||||
void AddIndexById(unsigned char Id, const char *KeyName);
|
||||
|
||||
void WalkIndices(IndexWalker callback, void *context);
|
||||
|
||||
IndexField *GetIndexByName(const char *name);
|
||||
IndexField *GetIndexById(unsigned char Id);
|
||||
using Scanner::SetWorkingIndexByName;
|
||||
using Scanner::SetWorkingIndexById;
|
||||
bool CheckIndexing(void);
|
||||
void DropIndexByName(const char *desc);
|
||||
void DropIndexById(unsigned char Id);
|
||||
void DropIndex(IndexField *Ptr);
|
||||
void IndexModified(void);
|
||||
|
||||
// Filters
|
||||
using Scanner::AddFilterByName;
|
||||
using Scanner::AddFilterById;
|
||||
using Scanner::AddFilterOp;
|
||||
using Scanner::RemoveFilters;
|
||||
|
||||
// Scanners
|
||||
Scanner *NewScanner();
|
||||
Scanner *GetDefaultScanner();
|
||||
void DeleteScanner(Scanner *scan);
|
||||
|
||||
// Misc
|
||||
using Scanner::FragmentationLevel;
|
||||
void Compact(int *progress = NULL);
|
||||
void SetGlobalLocateUpToDate(bool is);
|
||||
|
||||
// Row Cache
|
||||
void RowCache_Delete(int position);
|
||||
void RowCache_Remove(int position);
|
||||
void RowCache_Add(Record *record, int position);
|
||||
Record *RowCache_Get(int position);
|
||||
NDE_API void EnableRowCache();
|
||||
|
||||
// Searching
|
||||
void SetFieldSearchableById(unsigned char field_id, bool searchable);
|
||||
|
||||
int HasErrors()
|
||||
{
|
||||
return numErrors > 0;
|
||||
}
|
||||
int NumErrors()
|
||||
{
|
||||
return numErrors;
|
||||
}
|
||||
void IncErrorCount()
|
||||
{
|
||||
numErrors++;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
539
Src/nde/android/Vfs.cpp
Normal file
539
Src/nde/android/Vfs.cpp
Normal file
|
@ -0,0 +1,539 @@
|
|||
|
||||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Virtual File System
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
#include "../nde.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include "Vfs.h"
|
||||
|
||||
#ifndef EOF
|
||||
#define EOF -1
|
||||
#endif
|
||||
|
||||
/* the FILE (fopen/fwrite/etc) implementation for Mac and Linux */
|
||||
|
||||
|
||||
|
||||
VFILE *Vfnew(const char *fl, const char *mode, int Cached)
|
||||
{
|
||||
if (!fl) return NULL;
|
||||
VFILE *f = (VFILE *)malloc(sizeof(VFILE));
|
||||
if (!f)
|
||||
return NULL;
|
||||
memset(f, 0, sizeof(VFILE));
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
f->cached = Cached;
|
||||
#else
|
||||
f->cached = 1;
|
||||
#endif
|
||||
|
||||
if (!strchr(mode, '+'))
|
||||
{
|
||||
if (strchr(mode, 'r'))
|
||||
f->mode = VFS_READ | VFS_MUSTEXIST;
|
||||
if (strchr(mode, 'w'))
|
||||
f->mode = VFS_WRITE | VFS_CREATE | VFS_NEWCONTENT;
|
||||
if (strchr(mode, 'a'))
|
||||
f->mode = VFS_WRITE | VFS_CREATE | VFS_SEEKEOF;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strstr(mode, "r+"))
|
||||
f->mode = VFS_WRITE | VFS_MUSTEXIST;
|
||||
if (strstr(mode, "w+"))
|
||||
f->mode = VFS_WRITE | VFS_CREATE | VFS_NEWCONTENT;
|
||||
if (strstr(mode, "a+"))
|
||||
f->mode = VFS_WRITE | VFS_CREATE | VFS_SEEKEOF;
|
||||
}
|
||||
|
||||
if (f->mode == 0 || ((f->mode & VFS_READ) && (f->mode & VFS_WRITE)))
|
||||
{
|
||||
free(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf(f->lockname, sizeof(f->lockname), "%s.lock", fl);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
VFILE *Vfopen(VFILE *f, const char *fl, const char *mode, int Cached)
|
||||
{
|
||||
if (!f)
|
||||
{
|
||||
f = Vfnew(fl, mode, Cached);
|
||||
if (!f)
|
||||
return 0;
|
||||
}
|
||||
if (!f && !fl) return NULL;
|
||||
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
f->rfile = fopen(fl, mode);
|
||||
if (f->rfile)
|
||||
|
||||
f->filename = _strdup(fl);
|
||||
}
|
||||
else
|
||||
{
|
||||
free(f);
|
||||
return NULL;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (f->mode & VFS_MUSTEXIST)
|
||||
{
|
||||
if (access(fl, 0) != 0)
|
||||
{
|
||||
free(f);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(f->mode & VFS_NEWCONTENT))
|
||||
{
|
||||
FILE *pf;
|
||||
pf = fopen(fl, "rb");
|
||||
if (!pf)
|
||||
{
|
||||
f->data = (unsigned char *)calloc(VFILE_INC, 1);
|
||||
if (f->data == NULL)
|
||||
{
|
||||
free(f);
|
||||
return NULL;
|
||||
}
|
||||
f->filesize = 0;
|
||||
f->maxsize = VFILE_INC;
|
||||
}
|
||||
else
|
||||
{
|
||||
fseek(pf, 0, SEEK_END);
|
||||
f->filesize = ftell(pf);
|
||||
fseek(pf, 0, SEEK_SET);
|
||||
f->data = (unsigned char *)calloc(f->filesize, 1);
|
||||
if (f->data == NULL)
|
||||
{
|
||||
free(f);
|
||||
return NULL;
|
||||
}
|
||||
f->maxsize = f->filesize;
|
||||
fread(f->data, f->filesize, 1, pf);
|
||||
fclose(pf);
|
||||
}
|
||||
}
|
||||
|
||||
if (f->mode & VFS_SEEKEOF)
|
||||
f->ptr = f->filesize;
|
||||
|
||||
f->filename = strdup(fl);
|
||||
return f;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Vfclose(VFILE *f)
|
||||
{
|
||||
if (!f) return;
|
||||
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
free(f->filename);
|
||||
if (f->rfile)
|
||||
fclose(f->rfile);
|
||||
f->rfile=0;
|
||||
// free(f);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(f->mode & VFS_WRITE))
|
||||
{
|
||||
free(f->filename);
|
||||
free(f->data);
|
||||
//free(f);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Vsync(f);
|
||||
while (f->locks)
|
||||
Vfunlock(f, 1);
|
||||
|
||||
free(f->filename);
|
||||
free(f->data);
|
||||
//free(f);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
size_t Vfread(void *ptr, size_t size, VFILE *f)
|
||||
{
|
||||
if (!ptr || !f) return 0;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
return fread(ptr, 1, size, f->rfile);
|
||||
}
|
||||
#endif
|
||||
size_t s = size;
|
||||
if (!s) return 0;
|
||||
if (s + f->ptr > f->filesize)
|
||||
{
|
||||
//FUCKO: remove this
|
||||
if (!(f->ptr < f->filesize))
|
||||
{
|
||||
// if (!f->flushtable) // this would be ideal, if we could figure out f->flushtable
|
||||
// f->flushtable=MessageBox(g_hwnd,"DB read failed, DB may be corrupted.\r\n\r\n"
|
||||
// "Hit Retry to continue, or Cancel to clear the DB and start over","Winamp Library Error",MB_RETRYCANCEL) == IDCANCEL; //fucko
|
||||
//MessageBox(g_hwnd,"DB read failed, DB may be corrupted. If this error persists, remove all files from the library.",
|
||||
// "Winamp Library Error",MB_OK);
|
||||
return 0;
|
||||
}
|
||||
s = f->filesize - f->ptr;
|
||||
}
|
||||
memcpy(ptr, f->data+f->ptr, s);
|
||||
f->ptr += s;
|
||||
return (s/size);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Vfwrite(const void *ptr, size_t size, VFILE *f)
|
||||
{
|
||||
if (!ptr || !f) return;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
fwrite(ptr, size*n, f->rfile);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
f->dirty=1;
|
||||
if (size + f->ptr > f->maxsize)
|
||||
{
|
||||
// grow f->data,f->maxsize to be (size + f->ptr + VFILE_INC-1)&~(VFILE_INC-1)
|
||||
// instead of calling Vgrow again which gets kinda slow
|
||||
size_t newsize=(size + f->ptr + VFILE_INC-1)&~(VFILE_INC-1);
|
||||
f->data=(unsigned char *)realloc(f->data,newsize);
|
||||
if (f->data == NULL) return;
|
||||
memset(f->data+f->maxsize,0,newsize-f->maxsize);
|
||||
f->maxsize=newsize;
|
||||
}
|
||||
memcpy(f->data + f->ptr, ptr, size);
|
||||
f->ptr += size;
|
||||
if (f->ptr > f->filesize)
|
||||
f->filesize = f->ptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Vgrow(VFILE *f)
|
||||
{
|
||||
if (!f) return;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached) return;
|
||||
#endif
|
||||
f->data = (unsigned char *)realloc(f->data, f->maxsize + VFILE_INC);
|
||||
f->maxsize += VFILE_INC;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Vfputs(char *str, VFILE *f)
|
||||
{
|
||||
if (!f) return;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
fputs(str, f->rfile);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
Vfwrite(str, strlen(str), f);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Vfputc(char c, VFILE *f)
|
||||
{
|
||||
if (!f) return;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
fputc(c, f->rfile);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
Vfwrite(&c, 1, f);
|
||||
}
|
||||
|
||||
/* benski> unused:
|
||||
// not mac compliant
|
||||
//----------------------------------------------------------------------------
|
||||
char *Vfgets(char *dest, int n, VFILE *f) {
|
||||
if (!f) return NULL;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
#ifdef NDE_NOWIN32FILEIO
|
||||
return fgets(dest, n, f->rfile);
|
||||
#else
|
||||
#error port me!
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned char c=0;
|
||||
char *p;
|
||||
int l=0;
|
||||
|
||||
p = dest;
|
||||
while (l < n && !Vfeof(f)) {
|
||||
c = f->data[f->ptr];
|
||||
f->ptr++;
|
||||
*p = c;
|
||||
p++;
|
||||
l++;
|
||||
if (c == '\n') {
|
||||
if (!Vfeof(f) && f->data[f->ptr] == '\r') {
|
||||
f->ptr++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
*p=0;
|
||||
return dest;
|
||||
}
|
||||
*/
|
||||
|
||||
/* benski> unused:
|
||||
//----------------------------------------------------------------------------
|
||||
char Vfgetc(VFILE *f) {
|
||||
if (!f) return EOF;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
#ifdef NDE_NOWIN32FILEIO
|
||||
return fgetc(f->rfile);
|
||||
#else
|
||||
#error port me#
|
||||
#endif
|
||||
#endif
|
||||
if (!Vfeof(f))
|
||||
return f->data[f->ptr++];
|
||||
return EOF;
|
||||
}
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
unsigned long Vftell(VFILE *f)
|
||||
{
|
||||
if (!f) return (unsigned)-1;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
return ftell(f->rfile);
|
||||
}
|
||||
#endif
|
||||
return f->ptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Vfseek(VFILE *f, long i, int whence)
|
||||
{
|
||||
if (!f) return;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
fseek(f->rfile, i, whence);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
f->ptr = i;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
f->ptr += i;
|
||||
break;
|
||||
case SEEK_END:
|
||||
f->ptr = f->filesize+i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int Vfeof(VFILE *f)
|
||||
{
|
||||
if (!f) return -1;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
return feof(f->rfile);
|
||||
}
|
||||
#endif
|
||||
return (f->ptr >= f->filesize);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int Vsync(VFILE *f)
|
||||
{
|
||||
if (!f) return 0;
|
||||
if (!f->dirty) return 0;
|
||||
|
||||
if (f->mode & VFS_WRITE)
|
||||
{
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
int p=ftell(f->rfile);
|
||||
fclose(f->rfile);
|
||||
f->rfile = fopen(f->filename, "r+b");
|
||||
if (!f->rfile)
|
||||
return 1;
|
||||
fseek(f->rfile, p, SEEK_SET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
char newfn[1024], oldfn[1024];
|
||||
DWORD mypid=getpid();
|
||||
|
||||
snprintf(newfn,sizeof(newfn), "%s.n3w%08X",f->filename,mypid);
|
||||
snprintf(oldfn,sizeof(oldfn), "%s.o1d%08X",f->filename,mypid);
|
||||
|
||||
unlink(newfn);
|
||||
unlink(oldfn);
|
||||
|
||||
|
||||
tryagain:
|
||||
FILE *pf = fopen(newfn, "wb");
|
||||
if (!pf || fwrite(f->data, f->filesize, 1, pf) != 1)
|
||||
{
|
||||
if (pf) fclose(pf);
|
||||
|
||||
|
||||
printf("Error flushing DB to disk (is your drive full?)\n\nHit (R)etry to try again (recommended), or (C)ancel to abort (NOT recommended, and may leave the DB in an unuseable state)");
|
||||
fflush(stdout);
|
||||
char c;
|
||||
while (1)
|
||||
{
|
||||
scanf("%c", &c);
|
||||
// clear_stdin();
|
||||
c = toupper(c);
|
||||
if (c == 'R') goto tryagain;
|
||||
else if (c == 'C') break;
|
||||
}
|
||||
unlink(newfn);
|
||||
return 1;
|
||||
}
|
||||
fclose(pf);
|
||||
rename(f->filename,oldfn); // save old file
|
||||
|
||||
|
||||
|
||||
int rv=0;
|
||||
|
||||
tryagain2:
|
||||
if (rename(newfn,f->filename))
|
||||
{
|
||||
|
||||
printf("Error updating DB file on disk. This should never really happen\n\nHit (R)etry to try again (recommended), or (C)ancel to abort (NOT recommended, and may leave the DB in an unuseable state)");
|
||||
fflush(stdout);
|
||||
char c;
|
||||
while (1)
|
||||
{
|
||||
scanf("%c", &c);
|
||||
// clear_stdin();
|
||||
c = toupper(c);
|
||||
if (c == 'R') goto tryagain2;
|
||||
else if (c == 'C') break;
|
||||
}
|
||||
|
||||
rename(oldfn,f->filename); // restore old file
|
||||
rv=1;
|
||||
}
|
||||
|
||||
// clean up our temp files
|
||||
unlink(oldfn);
|
||||
unlink(newfn);
|
||||
|
||||
|
||||
//free(newfn);
|
||||
//free(oldfn);
|
||||
return rv;
|
||||
}
|
||||
f->dirty=0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Vfdestroy(VFILE *f)
|
||||
{
|
||||
// benski> TODO:
|
||||
if (f)
|
||||
{
|
||||
Vfclose(f);
|
||||
|
||||
while (f->locks)
|
||||
Vfunlock(f, 1);
|
||||
|
||||
// TODO if (f->mutex) CloseHandle(f->mutex);
|
||||
free(f);
|
||||
}
|
||||
}
|
||||
|
||||
// benski> TODO implement these with fopen
|
||||
|
||||
// returns 0 on failure
|
||||
int Vflock(VFILE *fl, bool is_sync)
|
||||
{
|
||||
#ifndef NO_TABLE_WIN32_LOCKING
|
||||
if (!fl) return 0;
|
||||
if (!is_sync && fl->cached)
|
||||
return 1;
|
||||
if (fl->locks++ == 0)
|
||||
{
|
||||
int retry_cnt=0;
|
||||
FILE *fFile;
|
||||
do
|
||||
{
|
||||
fFile = fopen(fl->lockname, "wb");
|
||||
if (fFile == 0) Sleep(100);
|
||||
}
|
||||
while (fFile == 0 && retry_cnt++ < 100); // try for 10 seconds
|
||||
|
||||
if (fFile == INVALID_HANDLE_VALUE) return 0; // db already locked, fail gracefully
|
||||
fl->lockFile = fFile;
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
void Vfunlock(VFILE *fl, bool is_sync)
|
||||
{
|
||||
#ifndef NO_TABLE_WIN32_LOCKING
|
||||
if (!is_sync && fl->cached)
|
||||
return;
|
||||
|
||||
if (--fl->locks == 0)
|
||||
{
|
||||
if (fl && fl->lockFile && fl->lockFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
fclose(fl->lockFile);
|
||||
unlink(fl->lockname);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
480
Src/nde/android/nde_c.cpp
Normal file
480
Src/nde/android/nde_c.cpp
Normal file
|
@ -0,0 +1,480 @@
|
|||
#include "nde_c.h"
|
||||
#include "../nde.h"
|
||||
|
||||
/* Database */
|
||||
nde_database_t NDE_CreateDatabase()
|
||||
{
|
||||
return (nde_database_t)new Database();
|
||||
}
|
||||
|
||||
void NDE_DestroyDatabase(nde_database_t db)
|
||||
{
|
||||
delete (Database *)db;
|
||||
}
|
||||
|
||||
nde_table_t NDE_Database_OpenTable(nde_database_t db, const char *filename, const char *indexname, int create, int cache)
|
||||
{
|
||||
Database *database = (Database *)db;
|
||||
if (database && filename)
|
||||
return (nde_table_t)database->OpenTable(filename, indexname, (BOOL)create, (BOOL)cache);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NDE_Database_CloseTable(nde_database_t db, nde_table_t t)
|
||||
{
|
||||
Database *database = (Database *)db;
|
||||
Table *table = (Table *)t;
|
||||
if (database && table)
|
||||
{
|
||||
database->CloseTable(table);
|
||||
}
|
||||
}
|
||||
/* Table */
|
||||
|
||||
nde_field_t NDE_Table_NewColumn(nde_table_t t, unsigned char id, const char *name, unsigned char type)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
return (nde_field_t)table->NewColumn(id, name, type, FALSE);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NDE_Table_PostColumns(nde_table_t t)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
table->PostColumns();
|
||||
}
|
||||
|
||||
void NDE_Table_AddIndexByID(nde_table_t t, unsigned char id, const char *name)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
table->AddIndexById(id, name);
|
||||
}
|
||||
|
||||
nde_scanner_t NDE_Table_CreateScanner(nde_table_t t)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
return (nde_scanner_t)table->NewScanner();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NDE_Table_DestroyScanner(nde_table_t t, nde_scanner_t s)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (table && scanner)
|
||||
table->DeleteScanner(scanner);
|
||||
}
|
||||
|
||||
void NDE_Table_Sync(nde_table_t t)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
table->Sync();
|
||||
}
|
||||
|
||||
int NDE_Table_GetRecordsCount(nde_table_t t)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
return table->GetRecordsCount();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
nde_field_t NDE_Table_GetColumnByID(nde_table_t t, unsigned char id)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
return (nde_field_t)table->GetColumnById(id);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
nde_field_t NDE_Table_GetColumnByName(nde_table_t t, const char *name)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table && name)
|
||||
return (nde_field_t)table->GetColumnByName(name);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NDE_Table_SetColumnSearchableByID(nde_table_t t, unsigned char id, int searchable)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
table->SetFieldSearchableById(id, !!searchable);
|
||||
}
|
||||
/* Scanner */
|
||||
int NDE_Scanner_Query(nde_scanner_t s, const char *query)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return scanner->Query(query);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NDE_Scanner_Search(nde_scanner_t s, const char *search_term)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
scanner->Search(search_term);
|
||||
}
|
||||
|
||||
const char *NDE_Scanner_GetLastQuery(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return scanner->GetLastQuery();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NDE_Scanner_GetRecordsCount(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return scanner->GetRecordsCount();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NDE_Scanner_New(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
scanner->New();
|
||||
}
|
||||
|
||||
void NDE_Scanner_Post(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
scanner->Post();
|
||||
}
|
||||
|
||||
void NDE_Scanner_First(nde_scanner_t s, int *killswitch)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
scanner->First(killswitch);
|
||||
}
|
||||
|
||||
void NDE_Scanner_Delete(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
scanner->Delete();
|
||||
}
|
||||
|
||||
void NDE_Scanner_Edit(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
scanner->Edit();
|
||||
}
|
||||
|
||||
int NDE_Scanner_EOF(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return scanner->Eof();
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
int NDE_Scanner_BOF(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return scanner->Bof();
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
nde_field_t NDE_Scanner_NewFieldByID(nde_scanner_t s, unsigned char id)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return (nde_field_t)scanner->NewFieldById(id, PERM_READWRITE);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
nde_field_t NDE_Scanner_NewFieldByName(nde_scanner_t s, const char *name)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return (nde_field_t)scanner->NewFieldByName(name, PERM_READWRITE);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
nde_field_t NDE_Scanner_GetFieldByID(nde_scanner_t s, unsigned char id)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return (nde_field_t)scanner->GetFieldById(id);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
nde_field_t NDE_Scanner_GetFieldByName(nde_scanner_t s, const char *name)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner && name)
|
||||
return (nde_field_t)scanner->GetFieldByName(name);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NDE_Scanner_AddFilterByID(nde_scanner_t s, unsigned char id, nde_field_t f, unsigned char filter_operation)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
Field *field = (Field *)f;
|
||||
if (scanner && field)
|
||||
scanner->AddFilterById(id, field, filter_operation);
|
||||
}
|
||||
|
||||
int NDE_Scanner_LocateInteger(nde_scanner_t s, unsigned char id, int from, int value, int *nskip, int compare_mode)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
{
|
||||
IntegerField field(value);
|
||||
return scanner->LocateByIdEx(id, from, &field, nskip, compare_mode);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NDE_Scanner_LocateString(nde_scanner_t s, unsigned char id, int from, const char *value, int *nskip, int compare_mode)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
{
|
||||
StringField field(value);
|
||||
return scanner->LocateByIdEx(id, from, &field, nskip, compare_mode);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int NDE_Scanner_LocateNDEString(nde_scanner_t s, unsigned char id, int from, char *value, int *nskip, int compare_mode)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
{
|
||||
StringField field(value, STRING_IS_NDESTRING);
|
||||
return scanner->LocateByIdEx(id, from, &field, nskip, compare_mode);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NDE_Scanner_LocateFilename(nde_scanner_t s, unsigned char id, int from, const char *value, int *nskip, int compare_mode)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
{
|
||||
FilenameField field(value);
|
||||
return scanner->LocateByIdEx(id, from, &field, nskip, compare_mode);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NDE_Scanner_LocateNDEFilename(nde_scanner_t s, unsigned char id, int from, char *value, int *nskip, int compare_mode)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
{
|
||||
FilenameField field(value, STRING_IS_NDESTRING);
|
||||
return scanner->LocateByIdEx(id, from, &field, nskip, compare_mode);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NDE_Scanner_LocateField(nde_scanner_t s, unsigned char id, int from, nde_field_t f, int *nskip, int compare_mode)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
Field *field = (Field *)f;
|
||||
if (scanner && field)
|
||||
{
|
||||
return scanner->LocateByIdEx(id, from, field, nskip, compare_mode);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NDE_Scanner_DeleteField(nde_scanner_t s, nde_field_t f)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
Field *field = (Field *)f;
|
||||
if (scanner && field)
|
||||
{
|
||||
scanner->DeleteField(field);
|
||||
}
|
||||
}
|
||||
|
||||
void NDE_Scanner_RemoveFilters(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
scanner->RemoveFilters();
|
||||
}
|
||||
|
||||
int NDE_Scanner_Next(nde_scanner_t s, int *killswitch)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return scanner->Next(killswitch);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
/* Filter functions */
|
||||
unsigned char NDE_Filter_GetID(nde_filter_t f)
|
||||
{
|
||||
Filter *filter = (Filter *)f;
|
||||
if (filter)
|
||||
return filter->GetId();
|
||||
else
|
||||
return FILTERS_INVALID; // right value but I'm not sure if it's the best constant name to use
|
||||
}
|
||||
|
||||
NDE_API unsigned char NDE_Filter_GetOp(nde_filter_t f)
|
||||
{
|
||||
Filter *filter = (Filter *)f;
|
||||
if (filter)
|
||||
return filter->GetOp();
|
||||
else
|
||||
return FILTERS_INVALID; // right value but I'm not sure if it's the best constant name to use
|
||||
}
|
||||
|
||||
NDE_API nde_field_t NDE_Filter_GetData(nde_filter_t f)
|
||||
{
|
||||
Filter *filter = (Filter *)f;
|
||||
if (filter)
|
||||
return (nde_field_t)filter->Data();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Field functions */
|
||||
unsigned char NDE_Field_GetType(nde_field_t f)
|
||||
{
|
||||
Field *field = (Field *)f;
|
||||
if (field)
|
||||
return field->GetType();
|
||||
else
|
||||
return FIELD_UNKNOWN;
|
||||
}
|
||||
|
||||
unsigned char NDE_Field_GetID(nde_field_t f)
|
||||
{
|
||||
Field *field = (Field *)f;
|
||||
if (field)
|
||||
return field->GetFieldId();
|
||||
else
|
||||
return FIELD_UNKNOWN;
|
||||
}
|
||||
|
||||
/* StringField functions */
|
||||
|
||||
void NDE_StringField_SetNDEString(nde_field_t f, char *nde_string)
|
||||
{
|
||||
StringField *field = (StringField *)(Field *)f;
|
||||
if (field)
|
||||
field->SetNDEString(nde_string);
|
||||
}
|
||||
|
||||
char *NDE_StringField_GetString(nde_field_t f)
|
||||
{
|
||||
StringField *field = (StringField *)(Field *)f;
|
||||
if (field)
|
||||
return field->GetString();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NDE_StringField_SetString(nde_field_t f, const char *str)
|
||||
{
|
||||
StringField *field = (StringField *)(Field *)f;
|
||||
if (field)
|
||||
field->SetString(str);
|
||||
}
|
||||
|
||||
/* IntegerField functions */
|
||||
void NDE_IntegerField_SetValue(nde_field_t f, int value)
|
||||
{
|
||||
IntegerField *field = (IntegerField *)(Field *)f;
|
||||
if (field)
|
||||
field->SetValue(value);
|
||||
}
|
||||
|
||||
int NDE_IntegerField_GetValue(nde_field_t f)
|
||||
{
|
||||
IntegerField *field = (IntegerField *)(Field *)f;
|
||||
if (field)
|
||||
return field->GetValue();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
nde_field_t NDE_IntegerField_Create(int value)
|
||||
{
|
||||
return (nde_field_t)new IntegerField(value);
|
||||
}
|
||||
|
||||
/* BinaryField */
|
||||
void *NDE_BinaryField_GetData(nde_field_t f, size_t *length)
|
||||
{
|
||||
BinaryField *field = (BinaryField *)(Field *)f;
|
||||
if (field)
|
||||
return (void *)field->GetData(length);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
void NDE_BinaryField_SetData(nde_field_t f, const void *data, size_t length)
|
||||
{
|
||||
BinaryField *field = (BinaryField *)(Field *)f;
|
||||
if (field)
|
||||
field->SetData((const uint8_t *)data, length);
|
||||
}
|
||||
|
||||
/* Int128Field */
|
||||
void NDE_Int128Field_SetValue(nde_field_t f, const void *value)
|
||||
{
|
||||
Int128Field *field = (Int128Field *)(Field *)f;
|
||||
if (field && value)
|
||||
field->SetValue(value);
|
||||
}
|
||||
|
||||
/* ColumnField */
|
||||
const char *NDE_ColumnField_GetFieldName(nde_field_t f)
|
||||
{
|
||||
ColumnField *field = (ColumnField *)(Field *)f;
|
||||
if (field)
|
||||
return field->GetFieldName();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char NDE_ColumnField_GetDataType(nde_field_t f)
|
||||
{
|
||||
ColumnField *field = (ColumnField *)(Field *)f;
|
||||
if (field)
|
||||
return field->GetDataType();
|
||||
else
|
||||
return FIELD_UNKNOWN;
|
||||
}
|
122
Src/nde/android/nde_c.h
Normal file
122
Src/nde/android/nde_c.h
Normal file
|
@ -0,0 +1,122 @@
|
|||
#pragma once
|
||||
/* C style API.
|
||||
|
||||
We'll eventually deprecate the C++ API as it presents a lot of linking challenges
|
||||
*/
|
||||
#include "../nde_defines.h"
|
||||
#include "../NDEString.h"
|
||||
#include <foundation/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
typedef struct nde_database_struct_t { } *nde_database_t;
|
||||
typedef struct nde_table_struct_t { } *nde_table_t;
|
||||
typedef struct nde_scanner_t_struct_t { } *nde_scanner_t;
|
||||
typedef struct nde_field_t_struct_t { } *nde_field_t;
|
||||
typedef struct nde_filter_struct_t { } *nde_filter_t;
|
||||
|
||||
/* Database functions */
|
||||
|
||||
NDE_API void NDE_Init();
|
||||
NDE_API void NDE_Quit();
|
||||
NDE_API nde_database_t NDE_CreateDatabase();
|
||||
NDE_API void NDE_DestroyDatabase(nde_database_t db);
|
||||
NDE_API nde_table_t NDE_Database_OpenTable(nde_database_t db, const char *filename, const char *filename_index, int create, int cache);
|
||||
|
||||
NDE_API void NDE_Database_CloseTable(nde_database_t db, nde_table_t table);
|
||||
|
||||
/* Table functions */
|
||||
NDE_API nde_field_t NDE_Table_NewColumn(nde_table_t table, unsigned char id, const char *name, unsigned char type);
|
||||
NDE_API void NDE_Table_PostColumns(nde_table_t table);
|
||||
NDE_API void NDE_Table_AddIndexByID(nde_table_t table, unsigned char id, const char *name);
|
||||
NDE_API nde_scanner_t NDE_Table_CreateScanner(nde_table_t table);
|
||||
NDE_API void NDE_Table_DestroyScanner(nde_table_t table, nde_scanner_t scanner);
|
||||
NDE_API void NDE_Table_Sync(nde_table_t table);
|
||||
#ifdef __cplusplus
|
||||
NDE_API void NDE_Table_Compact(nde_table_t table, int *progress=0);
|
||||
#else
|
||||
NDE_API void NDE_Table_Compact(nde_table_t table, int *progress);
|
||||
#endif
|
||||
NDE_API int NDE_Table_GetRecordsCount(nde_table_t table);
|
||||
NDE_API nde_field_t NDE_Table_GetColumnByID(nde_table_t table, unsigned char id);
|
||||
|
||||
NDE_API nde_field_t NDE_Table_GetColumnByName(nde_table_t table, const char *name);
|
||||
|
||||
NDE_API void NDE_Table_SetColumnSearchableByID(nde_table_t table, unsigned char id, int searchable);
|
||||
|
||||
/* Scanner functions */
|
||||
NDE_API int NDE_Scanner_Query(nde_scanner_t scanner, const char *query);
|
||||
NDE_API void NDE_Scanner_Search(nde_scanner_t scanner, const char *search_term);
|
||||
NDE_API const char *NDE_Scanner_GetLastQuery(nde_scanner_t scanner);
|
||||
NDE_API int NDE_Scanner_GetRecordsCount(nde_scanner_t scanner);
|
||||
NDE_API void NDE_Scanner_New(nde_scanner_t scanner);
|
||||
NDE_API void NDE_Scanner_Post(nde_scanner_t scanner);
|
||||
#ifdef __cplusplus
|
||||
NDE_API void NDE_Scanner_First(nde_scanner_t scanner, int *killswitch=0);
|
||||
NDE_API int NDE_Scanner_Next(nde_scanner_t scanner, int *killswitch=0);
|
||||
#else
|
||||
NDE_API void NDE_Scanner_First(nde_scanner_t scanner, int *killswitch);
|
||||
NDE_API int NDE_Scanner_Next(nde_scanner_t scanner, int *killswitch);
|
||||
#endif
|
||||
NDE_API void NDE_Scanner_Delete(nde_scanner_t scanner);
|
||||
NDE_API void NDE_Scanner_Edit(nde_scanner_t scanner);
|
||||
NDE_API int NDE_Scanner_EOF(nde_scanner_t scanner);
|
||||
NDE_API int NDE_Scanner_BOF(nde_scanner_t scanner);
|
||||
NDE_API nde_field_t NDE_Scanner_NewFieldByID(nde_scanner_t scanner, unsigned char id);
|
||||
NDE_API nde_field_t NDE_Scanner_NewFieldByName(nde_scanner_t scanner, const char *name);
|
||||
NDE_API nde_field_t NDE_Scanner_GetFieldByID(nde_scanner_t scanner, unsigned char id);
|
||||
NDE_API nde_field_t NDE_Scanner_GetFieldByName(nde_scanner_t scanner, const char *name);
|
||||
NDE_API void NDE_Scanner_AddFilterByID(nde_scanner_t scanner, unsigned char id, nde_field_t field, unsigned char filter_operation);
|
||||
#ifdef __cplusplus
|
||||
NDE_API int NDE_Scanner_LocateInteger(nde_scanner_t scanner, unsigned char id, int from, int value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
|
||||
NDE_API int NDE_Scanner_LocateString(nde_scanner_t scanner, unsigned char id, int from, const char *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
|
||||
NDE_API int NDE_Scanner_LocateNDEString(nde_scanner_t scanner, unsigned char id, int from, char *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
|
||||
NDE_API int NDE_Scanner_LocateFilename(nde_scanner_t scanner, unsigned char id, int from, const char *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
|
||||
NDE_API int NDE_Scanner_LocateNDEFilename(nde_scanner_t scanner, unsigned char id, int from, char *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
|
||||
NDE_API int NDE_Scanner_LocateField(nde_scanner_t scanner, unsigned char id, int from, nde_field_t field, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
|
||||
#else
|
||||
NDE_API int NDE_Scanner_LocateInteger(nde_scanner_t scanner, unsigned char id, int from, int value, int *nskip, int compare_mode);
|
||||
NDE_API int NDE_Scanner_LocateString(nde_scanner_t scanner, unsigned char id, int from, const char *value, int *nskip, int compare_mode);
|
||||
NDE_API int NDE_Scanner_LocateNDEString(nde_scanner_t scanner, unsigned char id, int from, char *value, int *nskip, int compare_mode);
|
||||
NDE_API int NDE_Scanner_LocateFilename(nde_scanner_t scanner, unsigned char id, int from, const char *value, int *nskip, int compare_mode);
|
||||
NDE_API int NDE_Scanner_LocateNDEFilename(nde_scanner_t scanner, unsigned char id, int from, char *value, int *nskip, int compare_mode);
|
||||
NDE_API int NDE_Scanner_LocateField(nde_scanner_t scanner, unsigned char id, int from, nde_field_t field, int *nskip, int compare_mode);
|
||||
#endif
|
||||
NDE_API void NDE_Scanner_DeleteField(nde_scanner_t scanner, nde_field_t field);
|
||||
NDE_API void NDE_Scanner_RemoveFilters(nde_scanner_t scanner);
|
||||
|
||||
/* Filter functions */
|
||||
NDE_API unsigned char NDE_Filter_GetID(nde_filter_t filter);
|
||||
NDE_API unsigned char NDE_Filter_GetOp(nde_filter_t filter);
|
||||
NDE_API nde_field_t NDE_Filter_GetData(nde_filter_t filter);
|
||||
|
||||
/* Field functions */
|
||||
NDE_API unsigned char NDE_Field_GetType(nde_field_t field);
|
||||
NDE_API unsigned char NDE_Field_GetID(nde_field_t field);
|
||||
|
||||
/* String Field functions */
|
||||
NDE_API char *NDE_StringField_GetString(nde_field_t field); /* returns non-const because it's an NDE string (reference counted, see ndestring.h) */
|
||||
NDE_API void NDE_StringField_SetNDEString(nde_field_t field, char *nde_string);
|
||||
NDE_API void NDE_StringField_SetString(nde_field_t field, const char *str);
|
||||
|
||||
/* IntegerField functions */
|
||||
NDE_API void NDE_IntegerField_SetValue(nde_field_t field, int value);
|
||||
NDE_API int NDE_IntegerField_GetValue(nde_field_t field);
|
||||
NDE_API nde_field_t NDE_IntegerField_Create(int value); /* mainly used for NDE_Scanner_AddFilterByID */
|
||||
|
||||
/* BinaryField functions */
|
||||
// on windows, the data pointer is optionally reference counted via ndestring (ndestring_retain if you plan on keeping it)
|
||||
NDE_API void *NDE_BinaryField_GetData(nde_field_t field, size_t *length);
|
||||
NDE_API void NDE_BinaryField_SetData(nde_field_t field, const void *data, size_t length);
|
||||
|
||||
/* Int128Field functions */
|
||||
NDE_API void NDE_Int128Field_SetValue(nde_field_t field, const void *value);
|
||||
|
||||
/* ColumnField functions */
|
||||
NDE_API const char *NDE_ColumnField_GetFieldName(nde_field_t field);
|
||||
NDE_API unsigned char NDE_ColumnField_GetDataType(nde_field_t field);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
12
Src/nde/android/nde_init.cpp
Normal file
12
Src/nde/android/nde_init.cpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#include "../nde_c.h"
|
||||
|
||||
/* NDE_Init isn't thread safe, be aware
|
||||
best to call on the main thread during initialization
|
||||
*/
|
||||
void NDE_Init()
|
||||
{
|
||||
}
|
||||
|
||||
void NDE_Quit()
|
||||
{
|
||||
}
|
48
Src/nde/android/record.h
Normal file
48
Src/nde/android/record.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
|
||||
/*
|
||||
|
||||
android (linux) implementation
|
||||
|
||||
*/
|
||||
#include "../field.h"
|
||||
#include "Vfs.h"
|
||||
#include <stdio.h>
|
||||
|
||||
class ColumnField;
|
||||
|
||||
class RecordBase
|
||||
{
|
||||
public:
|
||||
RecordBase();
|
||||
virtual ~RecordBase();
|
||||
Field *GetField(unsigned char ID);
|
||||
void Retain();
|
||||
void Release();
|
||||
void RemoveField(Field *field);
|
||||
void AddField(Field *field);
|
||||
|
||||
protected:
|
||||
void Undelete(void);
|
||||
|
||||
int InsertionPoint; // TODO: benski> might be able to pass this into WriteFields/WriteIndex
|
||||
int ref_count;
|
||||
typedef nu::PtrDeque2<Field> FieldList;
|
||||
FieldList Fields;
|
||||
};
|
||||
|
||||
|
||||
class Record : public RecordBase
|
||||
{
|
||||
public:
|
||||
Record(int RecordPos, int insertionPoint, VFILE *FileHandle,Table *p);
|
||||
bool InCache() { return ref_count > 1; }
|
||||
|
||||
ColumnField *GetColumnByName(const char *name);
|
||||
int WriteFields(Table *ParentTable, int RecordIndex);
|
||||
int WriteIndex(Table *ParentTable, int RecordIndex);
|
||||
void Delete(Table *ParentTable, int RecordIndex);
|
||||
typedef bool (*FieldsWalker)(Record *record, Field *entry, void *context);
|
||||
void WalkFields(FieldsWalker callback, void *context);
|
||||
};
|
||||
|
67
Src/nde/android/vfs.h
Normal file
67
Src/nde/android/vfs.h
Normal file
|
@ -0,0 +1,67 @@
|
|||
#ifndef __NDE_VFS_H
|
||||
#define __NDE_VFS_H
|
||||
|
||||
#include <foundation/types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
//#define NDE_ALLOW_NONCACHED
|
||||
|
||||
/*
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
#ifndef NDE_NOWIN32FILEIO
|
||||
#error NDE_ALLOW_NONCACHED at least for now requires NDE_NOWIN32FILEIO
|
||||
#endif
|
||||
#endif
|
||||
*/
|
||||
|
||||
#define VFILE_INC 65536
|
||||
|
||||
#define VFS_READ 1
|
||||
#define VFS_WRITE 2
|
||||
#define VFS_SEEKEOF 4
|
||||
#define VFS_CREATE 8
|
||||
#define VFS_NEWCONTENT 16
|
||||
#define VFS_MUSTEXIST 32
|
||||
|
||||
typedef struct {
|
||||
uint8_t *data;
|
||||
unsigned long ptr;
|
||||
unsigned long filesize;
|
||||
unsigned long maxsize;
|
||||
char *filename;
|
||||
char mode;
|
||||
int cached;
|
||||
int dirty;
|
||||
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
FILE *rfile;
|
||||
#endif
|
||||
FILE *lockFile;
|
||||
char lockname[1024];
|
||||
|
||||
int locks;
|
||||
} VFILE;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
VFILE *Vfnew(const char *fl, const char *mode, int Cached);
|
||||
VFILE *Vfopen(VFILE *f, const char *fl, const char *mode, int Cached);
|
||||
size_t Vfread(void *ptr, size_t size, VFILE *buf);
|
||||
void Vfseek(VFILE *fl, long i, int whence);
|
||||
unsigned long Vftell(VFILE *fl);
|
||||
void Vfclose(VFILE *fl);
|
||||
void Vfdestroy(VFILE *fl); // benski> TODO:
|
||||
void Vfwrite(const void *ptr, size_t size, VFILE *f);
|
||||
int Vfeof(VFILE *fl);
|
||||
int Vsync(VFILE *fl); // 1 on error updating
|
||||
int Vflock(VFILE *fl, bool is_sync=true); // returns 0 on failure
|
||||
void Vfunlock(VFILE *fl, bool is_sync=true);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
33
Src/nde/nde.def
Normal file
33
Src/nde/nde.def
Normal file
|
@ -0,0 +1,33 @@
|
|||
EXPORTS
|
||||
LinkedListEntry
|
||||
LinkedList
|
||||
Field
|
||||
ColumnField
|
||||
~ColumnField
|
||||
Compare
|
||||
ColumnField::GetDataType
|
||||
ColumnField::Compare
|
||||
ColumnField::GetFieldName
|
||||
ColumnField::GetUniqueDataScanner
|
||||
ColumnField::NewScanner
|
||||
ColumnField::DeleteScanner
|
||||
ColumnField::GetUnique
|
||||
IndexField
|
||||
StringField
|
||||
IntegerField
|
||||
GUIDField
|
||||
FloatField
|
||||
BooleanField
|
||||
BinaryField
|
||||
BitmapField
|
||||
PrivateField
|
||||
Record
|
||||
Scanner
|
||||
Table
|
||||
Index
|
||||
Filter
|
||||
Database
|
||||
~Database
|
||||
Database
|
||||
OpenTable
|
||||
NdeApi
|
168
Src/nde/nde.h
Normal file
168
Src/nde/nde.h
Normal file
|
@ -0,0 +1,168 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Nullsoft Database Engine - Codename: Neutrino
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Global Include File
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __NDE_H
|
||||
#define __NDE_H
|
||||
|
||||
// TODO: find better Mac preproc symbol
|
||||
#include "nde_defines.h"
|
||||
|
||||
extern const char *tSign;
|
||||
extern const char *iSign;
|
||||
|
||||
// Magic headers
|
||||
#define __TABLE_SIGNATURE__ tSign
|
||||
#define __INDEX_SIGNATURE__ iSign
|
||||
|
||||
// Linked list entry types
|
||||
#define UNKNOWN 0
|
||||
#define FIELD 1
|
||||
#define FILTER 2
|
||||
#define SCANNER 3
|
||||
|
||||
|
||||
|
||||
// Records constants
|
||||
#define NEW_RECORD -128
|
||||
#define FIELD_NOT_FOUND -1
|
||||
#define INVALID_RECORD -1
|
||||
#define NUM_SPECIAL_RECORDS 2 //
|
||||
#define FIELDS_RECORD_NUM 0
|
||||
#define INDEX_RECORD_NUM 1
|
||||
|
||||
// Index constants
|
||||
#define PRIMARY_INDEX 255
|
||||
#define QFIND_ENTIRE_SCOPE -1
|
||||
|
||||
|
||||
|
||||
|
||||
#define throwException(x) {}
|
||||
|
||||
#define FILTER_NOT 0
|
||||
#define FILTER_AND 1
|
||||
#define FILTER_OR 2
|
||||
|
||||
#define FILTERS_INVALID -1
|
||||
#define FILTERS_INCOMPLETE 1
|
||||
#define FILTERS_COMPLETE 1
|
||||
#define ADDFILTER_FAILED 2
|
||||
|
||||
// Permissions
|
||||
#define PERM_DENYALL 0
|
||||
#define PERM_READ 1
|
||||
#define PERM_READWRITE 3
|
||||
|
||||
|
||||
|
||||
// All our classes so we can foreward reference
|
||||
class NDE_API LinkedListEntry;
|
||||
class LinkedList;
|
||||
class Field;
|
||||
class ColumnField;
|
||||
class IndexField;
|
||||
class StringField;
|
||||
class IntegerField;
|
||||
class Int64Field;
|
||||
class Int128Field;
|
||||
class GUIDField;
|
||||
class FloatField;
|
||||
class BooleanField;
|
||||
class BinaryField;
|
||||
class Binary32Field;
|
||||
class BitmapField;
|
||||
class PrivateField;
|
||||
class FilenameField;
|
||||
class Record;
|
||||
class NDE_API Scanner;
|
||||
class Table;
|
||||
class Index;
|
||||
class Filter;
|
||||
class Database;
|
||||
|
||||
#if !defined (WIN32) && !defined(WIN64)
|
||||
#define NDE_NOWIN32FILEIO
|
||||
#define NO_TABLE_WIN32_LOCKING
|
||||
typedef int BOOL;
|
||||
typedef void* HANDLE;
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
#ifdef __APPLE__
|
||||
#include <bfc/platform/types.h>
|
||||
#else
|
||||
#include <foundation/types.h> // TODO
|
||||
#endif
|
||||
#define HINSTANCE int
|
||||
//#define HWND int
|
||||
#define DWORD int
|
||||
#define wsprintf sprintf
|
||||
#define OutputDebugString(x) ;
|
||||
#define GetCurrentProcessId() getpid()
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <strings.h>
|
||||
#include <string.h>
|
||||
#include <wchar.h>
|
||||
#include <sys/stat.h>
|
||||
void clear_stdin(void);
|
||||
|
||||
void CopyFile(const char *filename, const char *destfilename, BOOL b);
|
||||
void DeleteFile(const char *filename);
|
||||
BOOL MoveFile(const char *filename, const char *destfilename);
|
||||
void Sleep(int ms);
|
||||
|
||||
#define _stricmp strcasecmp
|
||||
#define strcmpi strcasecmp
|
||||
#define _strnicmp strncasecmp
|
||||
#define strncmpi strncasecmp
|
||||
|
||||
#define _wtoi(x) wcstol(x,0,10)
|
||||
// TODO: find case insensitive compare on Mac OS X
|
||||
#define _wcsicmp wcscmp
|
||||
#define _wcsnicmp wcsncmp
|
||||
|
||||
#define _MAX_PATH 8192
|
||||
#define _MAX_DRIVE 256
|
||||
#define _MAX_DIR 7424
|
||||
#define _MAX_FNAME 256
|
||||
#define _MAX_EXT 256
|
||||
|
||||
#define min(x,y) ((x > y) ? y : x)
|
||||
#define max(x,y) ((x < y) ? y : x)
|
||||
|
||||
#endif
|
||||
|
||||
// All our includes+
|
||||
|
||||
#include "Vfs.h"
|
||||
#include "LinkedList.h"
|
||||
#include "Field.h"
|
||||
#include "ColumnField.h"
|
||||
#include "IndexField.h"
|
||||
#include "StringField.h"
|
||||
#include "IntegerField.h"
|
||||
#include "Int64Field.h"
|
||||
#include "Int128Field.h"
|
||||
#include "BinaryField.h"
|
||||
#include "Binary32Field.h"
|
||||
#include "FilenameField.h"
|
||||
#include "Record.h"
|
||||
#include "Scanner.h"
|
||||
#include "Table.h"
|
||||
#include "Database.h"
|
||||
#include "Index.h"
|
||||
#include "Filter.h"
|
||||
#include "DBUtils.h"
|
||||
|
||||
|
||||
#endif
|
76
Src/nde/nde.rc
Normal file
76
Src/nde/nde.rc
Normal file
|
@ -0,0 +1,76 @@
|
|||
// Microsoft Visual C++ generated resource script.
|
||||
//
|
||||
#include "resource.h"
|
||||
|
||||
#define APSTUDIO_READONLY_SYMBOLS
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 2 resource.
|
||||
//
|
||||
#include "afxres.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#undef APSTUDIO_READONLY_SYMBOLS
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.S.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
#endif // English (U.S.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// English (U.K.) resources
|
||||
|
||||
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG)
|
||||
#ifdef _WIN32
|
||||
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK
|
||||
#pragma code_page(1252)
|
||||
#endif //_WIN32
|
||||
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// TEXTINCLUDE
|
||||
//
|
||||
|
||||
1 TEXTINCLUDE
|
||||
BEGIN
|
||||
"resource.h\0"
|
||||
END
|
||||
|
||||
2 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""afxres.h""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
3 TEXTINCLUDE
|
||||
BEGIN
|
||||
"#include ""version.rc2""\r\n"
|
||||
"\0"
|
||||
END
|
||||
|
||||
#endif // APSTUDIO_INVOKED
|
||||
|
||||
#endif // English (U.K.) resources
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#ifndef APSTUDIO_INVOKED
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Generated from the TEXTINCLUDE 3 resource.
|
||||
//
|
||||
#include "version.rc2"
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
#endif // not APSTUDIO_INVOKED
|
||||
|
77
Src/nde/nde.sln
Normal file
77
Src/nde/nde.sln
Normal file
|
@ -0,0 +1,77 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.29509.3
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nde", "nde.vcxproj", "{4D25C321-7F8B-424E-9899-D80A364BAF1A}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nx", "..\replicant\nx\nx.vcxproj", "{57C90706-B25D-4ACA-9B33-95CDB2427C27}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A} = {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nu", "..\replicant\nu\nu.vcxproj", "{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jnetlib", "..\replicant\jnetlib\jnetlib.vcxproj", "{E105A0A2-7391-47C5-86AC-718003524C3D}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A} = {0F9730E4-45DA-4BD2-A50A-403A4BC9751A}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "..\replicant\zlib\zlib.vcxproj", "{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Win32 = Debug|Win32
|
||||
Debug|x64 = Debug|x64
|
||||
Release|Win32 = Release|Win32
|
||||
Release|x64 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Debug|x64.Build.0 = Debug|x64
|
||||
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|Win32.Build.0 = Release|Win32
|
||||
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|x64.ActiveCfg = Release|x64
|
||||
{4D25C321-7F8B-424E-9899-D80A364BAF1A}.Release|x64.Build.0 = Release|x64
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Debug|x64.Build.0 = Debug|x64
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|Win32.Build.0 = Release|Win32
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|x64.ActiveCfg = Release|x64
|
||||
{57C90706-B25D-4ACA-9B33-95CDB2427C27}.Release|x64.Build.0 = Release|x64
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Debug|x64.Build.0 = Debug|x64
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|Win32.Build.0 = Release|Win32
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.ActiveCfg = Release|x64
|
||||
{F1F5CD60-0D5B-4CEA-9EEB-2F87FF9AA915}.Release|x64.Build.0 = Release|x64
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Debug|x64.Build.0 = Debug|x64
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|Win32.Build.0 = Release|Win32
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.ActiveCfg = Release|x64
|
||||
{E105A0A2-7391-47C5-86AC-718003524C3D}.Release|x64.Build.0 = Release|x64
|
||||
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|Win32.Build.0 = Debug|Win32
|
||||
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Debug|x64.Build.0 = Debug|x64
|
||||
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|Win32.ActiveCfg = Release|Win32
|
||||
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|Win32.Build.0 = Release|Win32
|
||||
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|x64.ActiveCfg = Release|x64
|
||||
{0F9730E4-45DA-4BD2-A50A-403A4BC9751A}.Release|x64.Build.0 = Release|x64
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {C4E799C1-027B-487B-8E1A-31F2D26A1AFE}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
321
Src/nde/nde.vcxproj
Normal file
321
Src/nde/nde.vcxproj
Normal file
|
@ -0,0 +1,321 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{4D25C321-7F8B-424E-9899-D80A364BAF1A}</ProjectGuid>
|
||||
<RootNamespace>nde</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0.19041.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
<IncludePath>$(IncludePath)</IncludePath>
|
||||
<LibraryPath>$(LibraryPath)</LibraryPath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(PlatformShortName)_$(Configuration)\</OutDir>
|
||||
<IntDir>$(PlatformShortName)_$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg">
|
||||
<VcpkgEnableManifest>false</VcpkgEnableManifest>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgConfiguration>Debug</VcpkgConfiguration>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
<VcpkgConfiguration>Debug</VcpkgConfiguration>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<VcpkgInstalledDir>
|
||||
</VcpkgInstalledDir>
|
||||
<VcpkgUseStatic>false</VcpkgUseStatic>
|
||||
<VcpkgTriplet>x86-windows-static-md</VcpkgTriplet>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>../Wasabi;../replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;NDE_EXPORTS;_WIN32_WINNT=0x601;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(ProjectDir)x86_Debug\$(ProjectName).lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\
|
||||
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\'</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>../Wasabi;../replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN64;_DEBUG;_WINDOWS;_USRDLL;NDE_EXPORTS;_WIN32_WINNT=0x601;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
|
||||
<RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
|
||||
<TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(ProjectDir)x64_Debug\$(ProjectName).lib</ImportLibrary>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\
|
||||
xcopy /Y /D $(IntDir)$(TargetName).pdb ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\'</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>../Wasabi;../replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;NDE_EXPORTS;_WIN32_WINNT=0x601;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4244;4018;4355;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(ProjectDir)x86_Release\$(ProjectName).lib</ImportLibrary>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\'</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>MinSpace</Optimization>
|
||||
<InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<AdditionalIncludeDirectories>../Wasabi;../replicant;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN64;NDEBUG;_WINDOWS;_USRDLL;NDE_EXPORTS;_WIN32_WINNT=0x601;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<StringPooling>true</StringPooling>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>None</DebugInformationFormat>
|
||||
<DisableSpecificWarnings>4244;4018;4355;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<GenerateDebugInformation>false</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(IntDir)$(TargetName).pdb</ProgramDatabaseFile>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<RandomizedBaseAddress>false</RandomizedBaseAddress>
|
||||
<ImportLibrary>$(ProjectDir)x64_Release\$(ProjectName).lib</ImportLibrary>
|
||||
<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
</Link>
|
||||
<PostBuildEvent>
|
||||
<Command>xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\ </Command>
|
||||
<Message>Post build event: 'xcopy /Y /D $(OutDir)$(TargetName)$(TargetExt) ..\..\Build\Winamp_$(PlatformShortName)_$(Configuration)\Shared\'</Message>
|
||||
</PostBuildEvent>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\replicant\nx\nx.vcxproj">
|
||||
<Project>{57c90706-b25d-4aca-9b33-95cdb2427c27}</Project>
|
||||
<CopyLocalSatelliteAssemblies>true</CopyLocalSatelliteAssemblies>
|
||||
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Wasabi\Wasabi.vcxproj">
|
||||
<Project>{3e0bfa8a-b86a-42e9-a33f-ec294f823f7f}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\nu\RingBuffer.cpp" />
|
||||
<ClCompile Include="Database.cpp" />
|
||||
<ClCompile Include="DBUtils.cpp" />
|
||||
<ClCompile Include="Field.cpp" />
|
||||
<ClCompile Include="Filter.cpp" />
|
||||
<ClCompile Include="Index.cpp" />
|
||||
<ClCompile Include="Int128Field.cpp" />
|
||||
<ClCompile Include="Int64Field.cpp" />
|
||||
<ClCompile Include="LinkedList.cpp" />
|
||||
<ClCompile Include="NDEString.cpp" />
|
||||
<ClCompile Include="win\Binary32Field.cpp" />
|
||||
<ClCompile Include="win\BinaryField.cpp" />
|
||||
<ClCompile Include="win\ColumnField.cpp" />
|
||||
<ClCompile Include="win\FilenameField.cpp" />
|
||||
<ClCompile Include="win\IndexField.cpp" />
|
||||
<ClCompile Include="win\IndexRecord.cpp" />
|
||||
<ClCompile Include="win\IntegerField.cpp" />
|
||||
<ClCompile Include="win\nde_c.cpp" />
|
||||
<ClCompile Include="win\nde_init.cpp" />
|
||||
<ClCompile Include="win\Query.cpp" />
|
||||
<ClCompile Include="win\Record.cpp" />
|
||||
<ClCompile Include="win\Scanner.cpp" />
|
||||
<ClCompile Include="win\StringField.cpp" />
|
||||
<ClCompile Include="win\Table.cpp" />
|
||||
<ClCompile Include="win\Vfs.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Database.h" />
|
||||
<ClInclude Include="DBUtils.h" />
|
||||
<ClInclude Include="Field.h" />
|
||||
<ClInclude Include="Filter.h" />
|
||||
<ClInclude Include="Index.h" />
|
||||
<ClInclude Include="Int128Field.h" />
|
||||
<ClInclude Include="Int64Field.h" />
|
||||
<ClInclude Include="LinkedList.h" />
|
||||
<ClInclude Include="nde.h" />
|
||||
<ClInclude Include="NDEString.h" />
|
||||
<ClInclude Include="nde_defines.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="win\Binary32Field.h" />
|
||||
<ClInclude Include="win\BinaryField.h" />
|
||||
<ClInclude Include="win\ColumnField.h" />
|
||||
<ClInclude Include="win\FilenameField.h" />
|
||||
<ClInclude Include="win\IndexField.h" />
|
||||
<ClInclude Include="win\IndexRecord.h" />
|
||||
<ClInclude Include="win\IntegerField.h" />
|
||||
<ClInclude Include="win\nde_c.h" />
|
||||
<ClInclude Include="win\Query.h" />
|
||||
<ClInclude Include="win\Record.h" />
|
||||
<ClInclude Include="win\Scanner.h" />
|
||||
<ClInclude Include="win\StringField.h" />
|
||||
<ClInclude Include="win\Table.h" />
|
||||
<ClInclude Include="win\Vfs.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="nde.rc" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
176
Src/nde/nde.vcxproj.filters
Normal file
176
Src/nde/nde.vcxproj.filters
Normal file
|
@ -0,0 +1,176 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<ClCompile Include="win\Binary32Field.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="win\BinaryField.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="win\ColumnField.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Database.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DBUtils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Field.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="win\FilenameField.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Filter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Index.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="win\IndexField.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="win\IndexRecord.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Int64Field.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Int128Field.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="win\IntegerField.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="LinkedList.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="win\nde_c.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="win\nde_init.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NDEString.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="win\Query.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="win\Record.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\nu\RingBuffer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="win\Scanner.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="win\StringField.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="win\Table.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="win\Vfs.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="win\Binary32Field.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="win\BinaryField.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="win\ColumnField.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Database.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DBUtils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Field.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="win\FilenameField.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Filter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Index.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="win\IndexField.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="win\IndexRecord.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Int64Field.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Int128Field.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="win\IntegerField.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="LinkedList.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="nde.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="win\nde_c.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="nde_defines.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NDEString.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="win\Query.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="win\Record.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="win\Scanner.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="win\StringField.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="win\Table.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="win\Vfs.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{9547ac55-c20b-484a-875b-0e9f6787c1f9}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Ressource Files">
|
||||
<UniqueIdentifier>{4278bf6e-44fa-4a76-a1e7-f3d3c96d4df0}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{e61e1158-723a-449b-b09f-bd63c3c611a7}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="nde.rc">
|
||||
<Filter>Ressource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
427
Src/nde/nde.xcodeproj/project.pbxproj
Normal file
427
Src/nde/nde.xcodeproj/project.pbxproj
Normal file
|
@ -0,0 +1,427 @@
|
|||
// !$*UTF8*$!
|
||||
{
|
||||
archiveVersion = 1;
|
||||
classes = {
|
||||
};
|
||||
objectVersion = 42;
|
||||
objects = {
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
0C0879F512A2D8AC001B1FD2 /* NDEString.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C0879F412A2D8AC001B1FD2 /* NDEString.h */; };
|
||||
0C087AB412A2DB4C001B1FD2 /* IndexRecord.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C087AB212A2DB4C001B1FD2 /* IndexRecord.cpp */; };
|
||||
0C087AB512A2DB4C001B1FD2 /* IndexRecord.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C087AB312A2DB4C001B1FD2 /* IndexRecord.h */; };
|
||||
0C087AC312A2DB85001B1FD2 /* nde_c.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C087AC012A2DB85001B1FD2 /* nde_c.cpp */; };
|
||||
0C087AC412A2DB85001B1FD2 /* nde_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C087AC112A2DB85001B1FD2 /* nde_c.h */; };
|
||||
0C087AC512A2DB85001B1FD2 /* nde_defines.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C087AC212A2DB85001B1FD2 /* nde_defines.h */; };
|
||||
0C087BCA12A2E962001B1FD2 /* Field.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C087BB612A2E962001B1FD2 /* Field.cpp */; };
|
||||
0C087BCB12A2E962001B1FD2 /* Field.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C087BB712A2E962001B1FD2 /* Field.h */; };
|
||||
0C087BD012A2E962001B1FD2 /* Int64Field.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C087BBC12A2E962001B1FD2 /* Int64Field.cpp */; };
|
||||
0C087BD112A2E962001B1FD2 /* Int64Field.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C087BBD12A2E962001B1FD2 /* Int64Field.h */; };
|
||||
0C087BD212A2E962001B1FD2 /* Int128Field.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C087BBE12A2E962001B1FD2 /* Int128Field.cpp */; };
|
||||
0C087BD312A2E962001B1FD2 /* Int128Field.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C087BBF12A2E962001B1FD2 /* Int128Field.h */; };
|
||||
0C89CB7912A5EFFA00366857 /* IndexField.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C89CB7712A5EFFA00366857 /* IndexField.cpp */; };
|
||||
0C89CB7A12A5EFFA00366857 /* IndexField.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C89CB7812A5EFFA00366857 /* IndexField.h */; };
|
||||
0C99F2380B93CE4C00AB7751 /* Crc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C99F2140B93CE4C00AB7751 /* Crc.cpp */; };
|
||||
0C99F2390B93CE4C00AB7751 /* CRC.H in Headers */ = {isa = PBXBuildFile; fileRef = 0C99F2150B93CE4C00AB7751 /* CRC.H */; };
|
||||
0C99F23A0B93CE4C00AB7751 /* Database.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C99F2160B93CE4C00AB7751 /* Database.cpp */; };
|
||||
0C99F23B0B93CE4C00AB7751 /* Database.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C99F2170B93CE4C00AB7751 /* Database.h */; };
|
||||
0C99F23C0B93CE4C00AB7751 /* DBUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C99F2180B93CE4C00AB7751 /* DBUtils.cpp */; };
|
||||
0C99F23D0B93CE4C00AB7751 /* DBUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C99F2190B93CE4C00AB7751 /* DBUtils.h */; };
|
||||
0C99F2410B93CE4C00AB7751 /* Filter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C99F21D0B93CE4C00AB7751 /* Filter.cpp */; };
|
||||
0C99F2420B93CE4C00AB7751 /* Filter.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C99F21E0B93CE4C00AB7751 /* Filter.h */; };
|
||||
0C99F2430B93CE4C00AB7751 /* Index.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C99F21F0B93CE4C00AB7751 /* Index.cpp */; };
|
||||
0C99F2440B93CE4C00AB7751 /* Index.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C99F2200B93CE4C00AB7751 /* Index.h */; };
|
||||
0C99F2490B93CE4C00AB7751 /* LinkedList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C99F2250B93CE4C00AB7751 /* LinkedList.cpp */; };
|
||||
0C99F24A0B93CE4C00AB7751 /* LinkedList.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C99F2260B93CE4C00AB7751 /* LinkedList.h */; };
|
||||
0C99F24B0B93CE4C00AB7751 /* nde.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C99F2270B93CE4C00AB7751 /* nde.h */; };
|
||||
0C99F24E0B93CE4C00AB7751 /* Record.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C99F22A0B93CE4C00AB7751 /* Record.cpp */; };
|
||||
0C99F24F0B93CE4C00AB7751 /* Record.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C99F22B0B93CE4C00AB7751 /* Record.h */; };
|
||||
0C99F2500B93CE4C00AB7751 /* Scanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C99F22C0B93CE4C00AB7751 /* Scanner.cpp */; };
|
||||
0C99F2510B93CE4C00AB7751 /* Scanner.h in Headers */ = {isa = PBXBuildFile; fileRef = 0C99F22D0B93CE4C00AB7751 /* Scanner.h */; };
|
||||
0CBA4FEF12A5DD6D008056C7 /* Binary32Field.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0CBA4FE912A5DD6D008056C7 /* Binary32Field.cpp */; };
|
||||
0CBA4FF012A5DD6D008056C7 /* Binary32Field.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CBA4FEA12A5DD6D008056C7 /* Binary32Field.h */; };
|
||||
0CBA4FF112A5DD6D008056C7 /* BinaryField.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0CBA4FEB12A5DD6D008056C7 /* BinaryField.cpp */; };
|
||||
0CBA4FF212A5DD6D008056C7 /* BinaryField.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CBA4FEC12A5DD6D008056C7 /* BinaryField.h */; };
|
||||
0CBA4FF312A5DD6D008056C7 /* ColumnField.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0CBA4FED12A5DD6D008056C7 /* ColumnField.cpp */; };
|
||||
0CBA4FF412A5DD6D008056C7 /* ColumnField.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CBA4FEE12A5DD6D008056C7 /* ColumnField.h */; };
|
||||
0CBA4FF912A5DD77008056C7 /* FilenameField.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0CBA4FF512A5DD77008056C7 /* FilenameField.cpp */; };
|
||||
0CBA4FFA12A5DD77008056C7 /* FilenameField.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CBA4FF612A5DD77008056C7 /* FilenameField.h */; };
|
||||
0CBA4FFB12A5DD77008056C7 /* StringField.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0CBA4FF712A5DD77008056C7 /* StringField.cpp */; };
|
||||
0CBA4FFC12A5DD77008056C7 /* StringField.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CBA4FF812A5DD77008056C7 /* StringField.h */; };
|
||||
0CBA4FFF12A5DD80008056C7 /* Vfs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0CBA4FFD12A5DD80008056C7 /* Vfs.cpp */; };
|
||||
0CBA500012A5DD80008056C7 /* Vfs.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CBA4FFE12A5DD80008056C7 /* Vfs.h */; };
|
||||
0CC9A3A712A723F500BCFEA6 /* IntegerField.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0CC9A3A512A723F500BCFEA6 /* IntegerField.cpp */; };
|
||||
0CC9A3A812A723F500BCFEA6 /* IntegerField.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CC9A3A612A723F500BCFEA6 /* IntegerField.h */; };
|
||||
0CC9A3AB12A7240400BCFEA6 /* Table.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0CC9A3A912A7240400BCFEA6 /* Table.cpp */; };
|
||||
0CC9A3AC12A7240400BCFEA6 /* Table.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CC9A3AA12A7240400BCFEA6 /* Table.h */; };
|
||||
0CC9A3AF12A7240900BCFEA6 /* Query.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0CC9A3AD12A7240900BCFEA6 /* Query.cpp */; };
|
||||
0CC9A3B012A7240900BCFEA6 /* Query.h in Headers */ = {isa = PBXBuildFile; fileRef = 0CC9A3AE12A7240900BCFEA6 /* Query.h */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
0C0879F412A2D8AC001B1FD2 /* NDEString.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NDEString.h; sourceTree = "<group>"; };
|
||||
0C087AB212A2DB4C001B1FD2 /* IndexRecord.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IndexRecord.cpp; sourceTree = "<group>"; };
|
||||
0C087AB312A2DB4C001B1FD2 /* IndexRecord.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IndexRecord.h; sourceTree = "<group>"; };
|
||||
0C087AC012A2DB85001B1FD2 /* nde_c.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = nde_c.cpp; sourceTree = "<group>"; };
|
||||
0C087AC112A2DB85001B1FD2 /* nde_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nde_c.h; sourceTree = "<group>"; };
|
||||
0C087AC212A2DB85001B1FD2 /* nde_defines.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nde_defines.h; sourceTree = "<group>"; };
|
||||
0C087BB612A2E962001B1FD2 /* Field.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Field.cpp; sourceTree = "<group>"; };
|
||||
0C087BB712A2E962001B1FD2 /* Field.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Field.h; sourceTree = "<group>"; };
|
||||
0C087BBC12A2E962001B1FD2 /* Int64Field.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Int64Field.cpp; sourceTree = "<group>"; };
|
||||
0C087BBD12A2E962001B1FD2 /* Int64Field.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Int64Field.h; sourceTree = "<group>"; };
|
||||
0C087BBE12A2E962001B1FD2 /* Int128Field.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Int128Field.cpp; sourceTree = "<group>"; };
|
||||
0C087BBF12A2E962001B1FD2 /* Int128Field.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Int128Field.h; sourceTree = "<group>"; };
|
||||
0C89CB7712A5EFFA00366857 /* IndexField.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IndexField.cpp; path = osx/IndexField.cpp; sourceTree = "<group>"; };
|
||||
0C89CB7812A5EFFA00366857 /* IndexField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IndexField.h; path = osx/IndexField.h; sourceTree = "<group>"; };
|
||||
0C99F2140B93CE4C00AB7751 /* Crc.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Crc.cpp; sourceTree = "<group>"; };
|
||||
0C99F2150B93CE4C00AB7751 /* CRC.H */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.h; path = CRC.H; sourceTree = "<group>"; };
|
||||
0C99F2160B93CE4C00AB7751 /* Database.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Database.cpp; sourceTree = "<group>"; };
|
||||
0C99F2170B93CE4C00AB7751 /* Database.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Database.h; sourceTree = "<group>"; };
|
||||
0C99F2180B93CE4C00AB7751 /* DBUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = DBUtils.cpp; sourceTree = "<group>"; };
|
||||
0C99F2190B93CE4C00AB7751 /* DBUtils.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = DBUtils.h; sourceTree = "<group>"; };
|
||||
0C99F21D0B93CE4C00AB7751 /* Filter.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Filter.cpp; sourceTree = "<group>"; };
|
||||
0C99F21E0B93CE4C00AB7751 /* Filter.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Filter.h; sourceTree = "<group>"; };
|
||||
0C99F21F0B93CE4C00AB7751 /* Index.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Index.cpp; sourceTree = "<group>"; };
|
||||
0C99F2200B93CE4C00AB7751 /* Index.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Index.h; sourceTree = "<group>"; };
|
||||
0C99F2250B93CE4C00AB7751 /* LinkedList.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = LinkedList.cpp; sourceTree = "<group>"; };
|
||||
0C99F2260B93CE4C00AB7751 /* LinkedList.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LinkedList.h; sourceTree = "<group>"; };
|
||||
0C99F2270B93CE4C00AB7751 /* nde.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = nde.h; sourceTree = "<group>"; };
|
||||
0C99F22A0B93CE4C00AB7751 /* Record.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Record.cpp; sourceTree = "<group>"; };
|
||||
0C99F22B0B93CE4C00AB7751 /* Record.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Record.h; sourceTree = "<group>"; };
|
||||
0C99F22C0B93CE4C00AB7751 /* Scanner.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Scanner.cpp; sourceTree = "<group>"; };
|
||||
0C99F22D0B93CE4C00AB7751 /* Scanner.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Scanner.h; sourceTree = "<group>"; };
|
||||
0CBA4FE912A5DD6D008056C7 /* Binary32Field.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Binary32Field.cpp; path = osx/Binary32Field.cpp; sourceTree = "<group>"; };
|
||||
0CBA4FEA12A5DD6D008056C7 /* Binary32Field.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Binary32Field.h; path = osx/Binary32Field.h; sourceTree = "<group>"; };
|
||||
0CBA4FEB12A5DD6D008056C7 /* BinaryField.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BinaryField.cpp; path = osx/BinaryField.cpp; sourceTree = "<group>"; };
|
||||
0CBA4FEC12A5DD6D008056C7 /* BinaryField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BinaryField.h; path = osx/BinaryField.h; sourceTree = "<group>"; };
|
||||
0CBA4FED12A5DD6D008056C7 /* ColumnField.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ColumnField.cpp; path = osx/ColumnField.cpp; sourceTree = "<group>"; };
|
||||
0CBA4FEE12A5DD6D008056C7 /* ColumnField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ColumnField.h; path = osx/ColumnField.h; sourceTree = "<group>"; };
|
||||
0CBA4FF512A5DD77008056C7 /* FilenameField.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = FilenameField.cpp; path = osx/FilenameField.cpp; sourceTree = "<group>"; };
|
||||
0CBA4FF612A5DD77008056C7 /* FilenameField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = FilenameField.h; path = osx/FilenameField.h; sourceTree = "<group>"; };
|
||||
0CBA4FF712A5DD77008056C7 /* StringField.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = StringField.cpp; path = osx/StringField.cpp; sourceTree = "<group>"; };
|
||||
0CBA4FF812A5DD77008056C7 /* StringField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = StringField.h; path = osx/StringField.h; sourceTree = "<group>"; };
|
||||
0CBA4FFD12A5DD80008056C7 /* Vfs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Vfs.cpp; path = osx/Vfs.cpp; sourceTree = "<group>"; };
|
||||
0CBA4FFE12A5DD80008056C7 /* Vfs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Vfs.h; path = osx/Vfs.h; sourceTree = "<group>"; };
|
||||
0CC9A3A512A723F500BCFEA6 /* IntegerField.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = IntegerField.cpp; path = osx/IntegerField.cpp; sourceTree = "<group>"; };
|
||||
0CC9A3A612A723F500BCFEA6 /* IntegerField.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = IntegerField.h; path = osx/IntegerField.h; sourceTree = "<group>"; };
|
||||
0CC9A3A912A7240400BCFEA6 /* Table.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Table.cpp; path = osx/Table.cpp; sourceTree = "<group>"; };
|
||||
0CC9A3AA12A7240400BCFEA6 /* Table.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Table.h; path = osx/Table.h; sourceTree = "<group>"; };
|
||||
0CC9A3AD12A7240900BCFEA6 /* Query.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Query.cpp; path = osx/Query.cpp; sourceTree = "<group>"; };
|
||||
0CC9A3AE12A7240900BCFEA6 /* Query.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Query.h; path = osx/Query.h; sourceTree = "<group>"; };
|
||||
D2AAC046055464E500DB518D /* libnde.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libnde.a; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
D289987405E68DCB004EDB86 /* Frameworks */ = {
|
||||
isa = PBXFrameworksBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXFrameworksBuildPhase section */
|
||||
|
||||
/* Begin PBXGroup section */
|
||||
08FB7794FE84155DC02AAC07 /* nde */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0C087BAD12A2E93E001B1FD2 /* Fields */,
|
||||
0C087ABE12A2DB7A001B1FD2 /* API */,
|
||||
0C087AA212A2DB0E001B1FD2 /* Records */,
|
||||
08FB7795FE84155DC02AAC07 /* Source */,
|
||||
C6A0FF2B0290797F04C91782 /* Documentation */,
|
||||
1AB674ADFE9D54B511CA2CBB /* Products */,
|
||||
);
|
||||
name = nde;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
08FB7795FE84155DC02AAC07 /* Source */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0C99F2140B93CE4C00AB7751 /* Crc.cpp */,
|
||||
0C99F2150B93CE4C00AB7751 /* CRC.H */,
|
||||
0C99F2160B93CE4C00AB7751 /* Database.cpp */,
|
||||
0C99F2170B93CE4C00AB7751 /* Database.h */,
|
||||
0C99F2180B93CE4C00AB7751 /* DBUtils.cpp */,
|
||||
0C99F2190B93CE4C00AB7751 /* DBUtils.h */,
|
||||
0C99F21D0B93CE4C00AB7751 /* Filter.cpp */,
|
||||
0C99F21E0B93CE4C00AB7751 /* Filter.h */,
|
||||
0C99F21F0B93CE4C00AB7751 /* Index.cpp */,
|
||||
0C99F2200B93CE4C00AB7751 /* Index.h */,
|
||||
0C99F2250B93CE4C00AB7751 /* LinkedList.cpp */,
|
||||
0C99F2260B93CE4C00AB7751 /* LinkedList.h */,
|
||||
0CC9A3AD12A7240900BCFEA6 /* Query.cpp */,
|
||||
0CC9A3AE12A7240900BCFEA6 /* Query.h */,
|
||||
0C99F2270B93CE4C00AB7751 /* nde.h */,
|
||||
0CC9A3A912A7240400BCFEA6 /* Table.cpp */,
|
||||
0CC9A3AA12A7240400BCFEA6 /* Table.h */,
|
||||
0C0879F412A2D8AC001B1FD2 /* NDEString.h */,
|
||||
0C99F22C0B93CE4C00AB7751 /* Scanner.cpp */,
|
||||
0C99F22D0B93CE4C00AB7751 /* Scanner.h */,
|
||||
0CBA4FFD12A5DD80008056C7 /* Vfs.cpp */,
|
||||
0CBA4FFE12A5DD80008056C7 /* Vfs.h */,
|
||||
);
|
||||
name = Source;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0C087AA212A2DB0E001B1FD2 /* Records */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0C087AB212A2DB4C001B1FD2 /* IndexRecord.cpp */,
|
||||
0C087AB312A2DB4C001B1FD2 /* IndexRecord.h */,
|
||||
0C99F22A0B93CE4C00AB7751 /* Record.cpp */,
|
||||
0C99F22B0B93CE4C00AB7751 /* Record.h */,
|
||||
);
|
||||
name = Records;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0C087ABE12A2DB7A001B1FD2 /* API */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0C087AC012A2DB85001B1FD2 /* nde_c.cpp */,
|
||||
0C087AC112A2DB85001B1FD2 /* nde_c.h */,
|
||||
0C087AC212A2DB85001B1FD2 /* nde_defines.h */,
|
||||
);
|
||||
name = API;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
0C087BAD12A2E93E001B1FD2 /* Fields */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
0CC9A3A512A723F500BCFEA6 /* IntegerField.cpp */,
|
||||
0CC9A3A612A723F500BCFEA6 /* IntegerField.h */,
|
||||
0C89CB7712A5EFFA00366857 /* IndexField.cpp */,
|
||||
0C89CB7812A5EFFA00366857 /* IndexField.h */,
|
||||
0CBA4FE912A5DD6D008056C7 /* Binary32Field.cpp */,
|
||||
0CBA4FEA12A5DD6D008056C7 /* Binary32Field.h */,
|
||||
0CBA4FEB12A5DD6D008056C7 /* BinaryField.cpp */,
|
||||
0CBA4FEC12A5DD6D008056C7 /* BinaryField.h */,
|
||||
0CBA4FED12A5DD6D008056C7 /* ColumnField.cpp */,
|
||||
0CBA4FEE12A5DD6D008056C7 /* ColumnField.h */,
|
||||
0C087BB612A2E962001B1FD2 /* Field.cpp */,
|
||||
0C087BB712A2E962001B1FD2 /* Field.h */,
|
||||
0CBA4FF512A5DD77008056C7 /* FilenameField.cpp */,
|
||||
0CBA4FF612A5DD77008056C7 /* FilenameField.h */,
|
||||
0C087BBE12A2E962001B1FD2 /* Int128Field.cpp */,
|
||||
0C087BBF12A2E962001B1FD2 /* Int128Field.h */,
|
||||
0C087BBC12A2E962001B1FD2 /* Int64Field.cpp */,
|
||||
0C087BBD12A2E962001B1FD2 /* Int64Field.h */,
|
||||
0CBA4FF712A5DD77008056C7 /* StringField.cpp */,
|
||||
0CBA4FF812A5DD77008056C7 /* StringField.h */,
|
||||
);
|
||||
name = Fields;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
1AB674ADFE9D54B511CA2CBB /* Products */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D2AAC046055464E500DB518D /* libnde.a */,
|
||||
);
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C6A0FF2B0290797F04C91782 /* Documentation */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
);
|
||||
name = Documentation;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXHeadersBuildPhase section */
|
||||
D2AAC043055464E500DB518D /* Headers */ = {
|
||||
isa = PBXHeadersBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0C99F2390B93CE4C00AB7751 /* CRC.H in Headers */,
|
||||
0C99F23B0B93CE4C00AB7751 /* Database.h in Headers */,
|
||||
0C99F23D0B93CE4C00AB7751 /* DBUtils.h in Headers */,
|
||||
0C99F2420B93CE4C00AB7751 /* Filter.h in Headers */,
|
||||
0C99F2440B93CE4C00AB7751 /* Index.h in Headers */,
|
||||
0C99F24A0B93CE4C00AB7751 /* LinkedList.h in Headers */,
|
||||
0C99F24B0B93CE4C00AB7751 /* nde.h in Headers */,
|
||||
0C99F24F0B93CE4C00AB7751 /* Record.h in Headers */,
|
||||
0C99F2510B93CE4C00AB7751 /* Scanner.h in Headers */,
|
||||
0C0879F512A2D8AC001B1FD2 /* NDEString.h in Headers */,
|
||||
0C087AB512A2DB4C001B1FD2 /* IndexRecord.h in Headers */,
|
||||
0C087AC412A2DB85001B1FD2 /* nde_c.h in Headers */,
|
||||
0C087AC512A2DB85001B1FD2 /* nde_defines.h in Headers */,
|
||||
0C087BCB12A2E962001B1FD2 /* Field.h in Headers */,
|
||||
0C087BD112A2E962001B1FD2 /* Int64Field.h in Headers */,
|
||||
0C087BD312A2E962001B1FD2 /* Int128Field.h in Headers */,
|
||||
0CBA4FF012A5DD6D008056C7 /* Binary32Field.h in Headers */,
|
||||
0CBA4FF212A5DD6D008056C7 /* BinaryField.h in Headers */,
|
||||
0CBA4FF412A5DD6D008056C7 /* ColumnField.h in Headers */,
|
||||
0CBA4FFA12A5DD77008056C7 /* FilenameField.h in Headers */,
|
||||
0CBA4FFC12A5DD77008056C7 /* StringField.h in Headers */,
|
||||
0CBA500012A5DD80008056C7 /* Vfs.h in Headers */,
|
||||
0C89CB7A12A5EFFA00366857 /* IndexField.h in Headers */,
|
||||
0CC9A3A812A723F500BCFEA6 /* IntegerField.h in Headers */,
|
||||
0CC9A3AC12A7240400BCFEA6 /* Table.h in Headers */,
|
||||
0CC9A3B012A7240900BCFEA6 /* Query.h in Headers */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXHeadersBuildPhase section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
D2AAC045055464E500DB518D /* nde */ = {
|
||||
isa = PBXNativeTarget;
|
||||
buildConfigurationList = 1DEB91EB08733DB70010E9CD /* Build configuration list for PBXNativeTarget "nde" */;
|
||||
buildPhases = (
|
||||
D2AAC043055464E500DB518D /* Headers */,
|
||||
D2AAC044055464E500DB518D /* Sources */,
|
||||
D289987405E68DCB004EDB86 /* Frameworks */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
dependencies = (
|
||||
);
|
||||
name = nde;
|
||||
productName = nde;
|
||||
productReference = D2AAC046055464E500DB518D /* libnde.a */;
|
||||
productType = "com.apple.product-type.library.static";
|
||||
};
|
||||
/* End PBXNativeTarget section */
|
||||
|
||||
/* Begin PBXProject section */
|
||||
08FB7793FE84155DC02AAC07 /* Project object */ = {
|
||||
isa = PBXProject;
|
||||
attributes = {
|
||||
ORGANIZATIONNAME = "Nullsoft, Inc.";
|
||||
};
|
||||
buildConfigurationList = 1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "nde" */;
|
||||
compatibilityVersion = "Xcode 2.4";
|
||||
developmentRegion = English;
|
||||
hasScannedForEncodings = 1;
|
||||
knownRegions = (
|
||||
English,
|
||||
Japanese,
|
||||
French,
|
||||
German,
|
||||
);
|
||||
mainGroup = 08FB7794FE84155DC02AAC07 /* nde */;
|
||||
projectDirPath = "";
|
||||
projectRoot = "";
|
||||
targets = (
|
||||
D2AAC045055464E500DB518D /* nde */,
|
||||
);
|
||||
};
|
||||
/* End PBXProject section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
D2AAC044055464E500DB518D /* Sources */ = {
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
0C99F2380B93CE4C00AB7751 /* Crc.cpp in Sources */,
|
||||
0C99F23A0B93CE4C00AB7751 /* Database.cpp in Sources */,
|
||||
0C99F23C0B93CE4C00AB7751 /* DBUtils.cpp in Sources */,
|
||||
0C99F2410B93CE4C00AB7751 /* Filter.cpp in Sources */,
|
||||
0C99F2430B93CE4C00AB7751 /* Index.cpp in Sources */,
|
||||
0C99F2490B93CE4C00AB7751 /* LinkedList.cpp in Sources */,
|
||||
0C99F24E0B93CE4C00AB7751 /* Record.cpp in Sources */,
|
||||
0C99F2500B93CE4C00AB7751 /* Scanner.cpp in Sources */,
|
||||
0C087AB412A2DB4C001B1FD2 /* IndexRecord.cpp in Sources */,
|
||||
0C087AC312A2DB85001B1FD2 /* nde_c.cpp in Sources */,
|
||||
0C087BCA12A2E962001B1FD2 /* Field.cpp in Sources */,
|
||||
0C087BD012A2E962001B1FD2 /* Int64Field.cpp in Sources */,
|
||||
0C087BD212A2E962001B1FD2 /* Int128Field.cpp in Sources */,
|
||||
0CBA4FEF12A5DD6D008056C7 /* Binary32Field.cpp in Sources */,
|
||||
0CBA4FF112A5DD6D008056C7 /* BinaryField.cpp in Sources */,
|
||||
0CBA4FF312A5DD6D008056C7 /* ColumnField.cpp in Sources */,
|
||||
0CBA4FF912A5DD77008056C7 /* FilenameField.cpp in Sources */,
|
||||
0CBA4FFB12A5DD77008056C7 /* StringField.cpp in Sources */,
|
||||
0CBA4FFF12A5DD80008056C7 /* Vfs.cpp in Sources */,
|
||||
0C89CB7912A5EFFA00366857 /* IndexField.cpp in Sources */,
|
||||
0CC9A3A712A723F500BCFEA6 /* IntegerField.cpp in Sources */,
|
||||
0CC9A3AB12A7240400BCFEA6 /* Table.cpp in Sources */,
|
||||
0CC9A3AF12A7240900BCFEA6 /* Query.cpp in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
/* End PBXSourcesBuildPhase section */
|
||||
|
||||
/* Begin XCBuildConfiguration section */
|
||||
1DEB91EC08733DB70010E9CD /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
COPY_PHASE_STRIP = NO;
|
||||
GCC_DYNAMIC_NO_PIC = NO;
|
||||
GCC_ENABLE_FIX_AND_CONTINUE = YES;
|
||||
GCC_MODEL_TUNING = G5;
|
||||
GCC_OPTIMIZATION_LEVEL = 0;
|
||||
INSTALL_PATH = /usr/local/lib;
|
||||
PRODUCT_NAME = nde;
|
||||
ZERO_LINK = YES;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
1DEB91ED08733DB70010E9CD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)";
|
||||
ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc";
|
||||
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
|
||||
GCC_MODEL_TUNING = G5;
|
||||
INSTALL_PATH = /usr/local/lib;
|
||||
PRODUCT_NAME = nde;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
1DEB91F008733DB70010E9CD /* Debug */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ARCHS = "$(ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1)";
|
||||
ARCHS_STANDARD_32_64_BIT_PRE_XCODE_3_1 = "x86_64 i386 ppc";
|
||||
GCC_ENABLE_CPP_EXCEPTIONS = NO;
|
||||
GCC_ENABLE_CPP_RTTI = NO;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = ../Wasabi;
|
||||
PREBINDING = NO;
|
||||
SDKROOT = /Developer/SDKs/MacOSX10.5.sdk;
|
||||
};
|
||||
name = Debug;
|
||||
};
|
||||
1DEB91F108733DB70010E9CD /* Release */ = {
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ARCHS = "$(ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1)";
|
||||
ARCHS_STANDARD_64_BIT_PRE_XCODE_3_1 = x86_64;
|
||||
GCC_ENABLE_CPP_EXCEPTIONS = NO;
|
||||
GCC_ENABLE_CPP_RTTI = NO;
|
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES;
|
||||
GCC_WARN_UNUSED_VARIABLE = YES;
|
||||
HEADER_SEARCH_PATHS = ../Wasabi;
|
||||
PREBINDING = NO;
|
||||
SDKROOT = /Developer/SDKs/MacOSX10.5.sdk;
|
||||
};
|
||||
name = Release;
|
||||
};
|
||||
/* End XCBuildConfiguration section */
|
||||
|
||||
/* Begin XCConfigurationList section */
|
||||
1DEB91EB08733DB70010E9CD /* Build configuration list for PBXNativeTarget "nde" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
1DEB91EC08733DB70010E9CD /* Debug */,
|
||||
1DEB91ED08733DB70010E9CD /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
1DEB91EF08733DB70010E9CD /* Build configuration list for PBXProject "nde" */ = {
|
||||
isa = XCConfigurationList;
|
||||
buildConfigurations = (
|
||||
1DEB91F008733DB70010E9CD /* Debug */,
|
||||
1DEB91F108733DB70010E9CD /* Release */,
|
||||
);
|
||||
defaultConfigurationIsVisible = 0;
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
|
||||
}
|
8
Src/nde/nde_c.h
Normal file
8
Src/nde/nde_c.h
Normal file
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
#ifdef __APPLE__
|
||||
#include "osx/nde_c.h"
|
||||
#elif defined(_WIN32)
|
||||
#include "win/nde_c.h"
|
||||
#elif defined(__ANDROID__)
|
||||
#include "android/nde_c.h"
|
||||
#endif
|
69
Src/nde/nde_defines.h
Normal file
69
Src/nde/nde_defines.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
#pragma once
|
||||
/* important defines and enums that are shared between the C++ api and the C api */
|
||||
|
||||
#define NDE_CACHE TRUE
|
||||
#define NDE_NOCACHE FALSE
|
||||
|
||||
#define NDE_OPEN_ALWAYS TRUE
|
||||
#define NDE_OPEN_EXISTING FALSE
|
||||
|
||||
#if defined(WIN32_NOLIB) || !defined(WIN32) && !defined(WIN64)
|
||||
#define NDE_API
|
||||
#else
|
||||
#ifdef NDE_EXPORTS
|
||||
#define NDE_API __declspec(dllexport)
|
||||
#else
|
||||
#define NDE_API __declspec(dllimport)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Field types
|
||||
enum
|
||||
{
|
||||
FIELD_COLUMN = 0,
|
||||
FIELD_INDEX = 1,
|
||||
FIELD_REDIRECTOR =2,
|
||||
FIELD_STRING =3,
|
||||
FIELD_INTEGER = 4,
|
||||
FIELD_BOOLEAN = 5,
|
||||
FIELD_BINARY =6, // max size 65536
|
||||
FIELD_GUID =7,
|
||||
FIELD_PRIVATE = 8,
|
||||
FIELD_BITMAP =6,
|
||||
FIELD_FLOAT = 9,
|
||||
FIELD_DATETIME =10,
|
||||
FIELD_LENGTH =11,
|
||||
FIELD_FILENAME =12,
|
||||
FIELD_INT64 = 13,
|
||||
FIELD_BINARY32 =14, // binary field, but 32bit sizes instead of 16bit
|
||||
FIELD_INT128 = 15, // mainly for storing MD5 hashes
|
||||
FIELD_UNKNOWN = 255,
|
||||
FIELD_CLONE = 255,// internal use
|
||||
};
|
||||
|
||||
// Filter types
|
||||
enum {
|
||||
FILTER_NONE = 100,
|
||||
FILTER_EQUALS,
|
||||
FILTER_NOTEQUALS,
|
||||
FILTER_CONTAINS,
|
||||
FILTER_NOTCONTAINS,
|
||||
FILTER_ABOVE,
|
||||
FILTER_BELOW,
|
||||
FILTER_ABOVEOREQUAL,
|
||||
FILTER_BELOWOREQUAL,
|
||||
FILTER_BEGINS,
|
||||
FILTER_ENDS,
|
||||
FILTER_LIKE,
|
||||
FILTER_ISEMPTY,
|
||||
FILTER_ISNOTEMPTY,
|
||||
FILTER_BEGINSLIKE,
|
||||
};
|
||||
|
||||
// compare modes
|
||||
#define COMPARE_MODE_CONTAINS 1
|
||||
#define COMPARE_MODE_EXACT 2
|
||||
#define COMPARE_MODE_STARTS 3
|
||||
|
||||
// scanner 'from' special constant
|
||||
#define FIRST_RECORD -1
|
78
Src/nde/osx/Binary32Field.cpp
Normal file
78
Src/nde/osx/Binary32Field.cpp
Normal file
|
@ -0,0 +1,78 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Binary32Field Class
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "nde.h"
|
||||
#include "Binary32Field.h"
|
||||
#include "ndestring.h"
|
||||
//---------------------------------------------------------------------------
|
||||
Binary32Field::Binary32Field(const uint8_t *_Data, size_t len) : BinaryField(_Data, len)
|
||||
{
|
||||
InitField();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Binary32Field::InitField(void)
|
||||
{
|
||||
Type = FIELD_BINARY32;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Binary32Field::Binary32Field()
|
||||
{
|
||||
InitField();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Binary32Field::ReadTypedData(const uint8_t *data, size_t len)
|
||||
{
|
||||
uint32_t c;
|
||||
size_t pos = 0;
|
||||
|
||||
CHECK_INT(len); //len-=4;
|
||||
c = GET_INT(); pos += 4;
|
||||
if (c && c<=len)
|
||||
{
|
||||
size_t size = c;
|
||||
uint8_t *buf = (uint8_t *)malloc(size);
|
||||
GET_BINARY(buf, data, c, pos);
|
||||
Data = CFDataCreateWithBytesNoCopy(NULL, buf, size, kCFAllocatorMalloc);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Binary32Field::WriteTypedData(uint8_t *data, size_t len)
|
||||
{
|
||||
uint32_t c;
|
||||
size_t pos = 0;
|
||||
|
||||
CHECK_INT(len); //len-=4;
|
||||
|
||||
size_t Size = CFDataGetLength(Data);
|
||||
if (Data && Size<=len)
|
||||
{
|
||||
c = CFDataGetLength(Data);
|
||||
PUT_INT(c); pos += 4;
|
||||
CFDataGetBytes(Data, CFRangeMake(0, Size), data+pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
PUT_INT(0);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
size_t Binary32Field::GetDataSize(void)
|
||||
{
|
||||
if (!Data)
|
||||
return 4;
|
||||
return CFDataGetLength(Data) + 4;
|
||||
}
|
32
Src/nde/osx/Binary32Field.h
Normal file
32
Src/nde/osx/Binary32Field.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Binary32Field Class Prototypes
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __NDE_BINARY32FIELD_H
|
||||
#define __NDE_BINARY32FIELD_H
|
||||
|
||||
#include "BinaryField.h"
|
||||
#include <bfc/platform/types.h>
|
||||
|
||||
class Binary32Field : public BinaryField
|
||||
{
|
||||
protected:
|
||||
virtual void ReadTypedData(const uint8_t *, size_t len);
|
||||
virtual void WriteTypedData(uint8_t *, size_t len);
|
||||
virtual size_t GetDataSize(void);
|
||||
void InitField(void);
|
||||
|
||||
public:
|
||||
Binary32Field(const uint8_t *Data, size_t len);
|
||||
Binary32Field();
|
||||
};
|
||||
|
||||
#endif
|
172
Src/nde/osx/BinaryField.cpp
Normal file
172
Src/nde/osx/BinaryField.cpp
Normal file
|
@ -0,0 +1,172 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
BinaryField Class
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "../nde.h"
|
||||
#include "BinaryField.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
BinaryField::BinaryField(const uint8_t *_Data, int len)
|
||||
{
|
||||
InitField();
|
||||
Type = FIELD_BINARY;
|
||||
if (_Data && len > 0)
|
||||
{
|
||||
Data = CFDataCreate(NULL, _Data, len);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void BinaryField::InitField(void)
|
||||
{
|
||||
Type = FIELD_BINARY;
|
||||
Data = NULL;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
BinaryField::BinaryField()
|
||||
{
|
||||
InitField();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
BinaryField::~BinaryField()
|
||||
{
|
||||
CFRelease(Data);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void BinaryField::ReadTypedData(const uint8_t *data, size_t len)
|
||||
{
|
||||
unsigned short c;
|
||||
int pos = 0;
|
||||
|
||||
CHECK_SHORT(len);
|
||||
|
||||
c = GET_SHORT(); pos += 2;
|
||||
if (c && c<=len)
|
||||
{
|
||||
Data = CFDataCreate(NULL, data+pos, c);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void BinaryField::WriteTypedData(uint8_t *data, size_t len)
|
||||
{
|
||||
unsigned short c;
|
||||
size_t pos = 0;
|
||||
|
||||
CHECK_SHORT(len);
|
||||
|
||||
size_t Size = CFDataGetLength(Data);
|
||||
if (Data && Size<=len)
|
||||
{
|
||||
c = CFDataGetLength(Data);
|
||||
PUT_SHORT(c); pos += 2;
|
||||
CFDataGetBytes(Data, CFRangeMake(0, Size), data+pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
PUT_SHORT(0);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
const uint8_t *BinaryField::GetData(size_t *len)
|
||||
{
|
||||
if (len)
|
||||
*len = CFDataGetLength(Data);
|
||||
return CFDataGetBytePtr(Data);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void BinaryField::SetData(const uint8_t *_Data, size_t len)
|
||||
{
|
||||
if (!_Data || !len) return;
|
||||
if (Data)
|
||||
CFRelease(Data);
|
||||
Data = CFDataCreate(NULL, _Data, len);
|
||||
}
|
||||
|
||||
CFDataRef BinaryField::GetCFData()
|
||||
{
|
||||
return Data;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
size_t BinaryField::GetDataSize(void)
|
||||
{
|
||||
if (!Data) return 2;
|
||||
return CFDataGetLength(Data) + 2;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int BinaryField::Compare(Field *Entry)
|
||||
{
|
||||
if (!Entry) return -1;
|
||||
size_t compare_length;
|
||||
const uint8_t *compare_data = ((BinaryField*)Entry)->GetData(&compare_length);
|
||||
|
||||
size_t size;
|
||||
const uint8_t *data = GetData(&size);
|
||||
return memcmp(data, compare_data, min(compare_length, size));
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
bool BinaryField::ApplyFilter(Field *FilterData, int op)
|
||||
{
|
||||
size_t l, s;
|
||||
const uint8_t *p = ((BinaryField *)FilterData)->GetData(&l);
|
||||
const uint8_t *d = GetData(&s);
|
||||
if (!p)
|
||||
p = (const uint8_t *)"";
|
||||
if (!d)
|
||||
d = (const uint8_t *)"";
|
||||
bool r;
|
||||
switch (op)
|
||||
{
|
||||
case FILTER_EQUALS:
|
||||
if (l != s)
|
||||
r = false;
|
||||
else
|
||||
r = !memcmp(d, p, min(s, l));
|
||||
break;
|
||||
case FILTER_CONTAINS:
|
||||
if (l > s)
|
||||
r = FALSE;
|
||||
else
|
||||
r = !!memmem(d, p, s, l);
|
||||
break;
|
||||
case FILTER_ABOVE:
|
||||
r = (memcmp(d, p, min(s, l)) > 0);
|
||||
break;
|
||||
case FILTER_BELOW:
|
||||
r = (memcmp(d, p, min(s, l)) < 0);
|
||||
break;
|
||||
case FILTER_BELOWOREQUAL:
|
||||
r = (memcmp(d, p, min(s, l)) <= 0);
|
||||
break;
|
||||
case FILTER_ABOVEOREQUAL:
|
||||
r = (memcmp(d, p, min(s, l)) >= 0);
|
||||
break;
|
||||
case FILTER_ISEMPTY:
|
||||
r = (s == 0);
|
||||
break;
|
||||
case FILTER_ISNOTEMPTY:
|
||||
r = (s != 0);
|
||||
break;
|
||||
default:
|
||||
r = true;
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
38
Src/nde/osx/BinaryField.h
Normal file
38
Src/nde/osx/BinaryField.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
BinaryField Class Prototypes
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __BINARYFIELD_H
|
||||
#define __BINARYFIELD_H
|
||||
|
||||
#include "Field.h"
|
||||
#include <bfc/platform/types.h>
|
||||
class BinaryField : public Field
|
||||
{
|
||||
protected:
|
||||
virtual void ReadTypedData(const uint8_t *, size_t len);
|
||||
virtual void WriteTypedData(uint8_t *, size_t len);
|
||||
virtual size_t GetDataSize(void);
|
||||
virtual int Compare(Field *Entry);
|
||||
virtual bool ApplyFilter(Field *Data, int flags);
|
||||
void InitField(void);
|
||||
CFDataRef Data;
|
||||
|
||||
public:
|
||||
~BinaryField();
|
||||
BinaryField(const uint8_t *Data, int len);
|
||||
BinaryField();
|
||||
const uint8_t *GetData(size_t *len);
|
||||
void SetData(const uint8_t *Data, size_t len);
|
||||
CFDataRef GetCFData();
|
||||
};
|
||||
|
||||
#endif
|
160
Src/nde/osx/ColumnField.cpp
Normal file
160
Src/nde/osx/ColumnField.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
ColumnField Class
|
||||
Mac OS X implementation
|
||||
|
||||
Field data layout:
|
||||
[1 byte] Field Type
|
||||
[1 byte] Unused (maybe convert to 'searchable')
|
||||
[1 byte] Name Length
|
||||
[Name Length bytes] Name (UTF-8)
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "../nde.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
ColumnField::ColumnField(unsigned char FieldID, CFStringRef FieldName, unsigned char FieldType, Table *parentTable)
|
||||
{
|
||||
InitField();
|
||||
Type = FIELD_COLUMN;
|
||||
MyType = FieldType;
|
||||
Name = (CFStringRef)CFRetain(FieldName);
|
||||
ID = FieldID;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void ColumnField::InitField(void)
|
||||
{
|
||||
searchable = false;
|
||||
MyType = FIELD_UNKNOWN;
|
||||
Type = FIELD_COLUMN;
|
||||
Name = NULL;
|
||||
ID = 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
ColumnField::ColumnField()
|
||||
{
|
||||
InitField();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
ColumnField::~ColumnField()
|
||||
{
|
||||
if (Name)
|
||||
CFRelease(Name);
|
||||
}
|
||||
|
||||
void ColumnField::SetSearchable(bool val)
|
||||
{
|
||||
searchable=val;
|
||||
}
|
||||
|
||||
bool ColumnField::IsSearchableField() const
|
||||
{
|
||||
return searchable;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void ColumnField::ReadTypedData(const uint8_t *data, size_t len)
|
||||
{
|
||||
unsigned char c;
|
||||
int pos=0;
|
||||
|
||||
CHECK_CHAR(len);
|
||||
MyType = GET_CHAR(); pos++;
|
||||
|
||||
CHECK_CHAR(len);
|
||||
pos++;
|
||||
|
||||
CHECK_CHAR(len);
|
||||
c = GET_CHAR(); pos++;
|
||||
if (c)
|
||||
{
|
||||
CHECK_BIN(len, c);
|
||||
if (Name)
|
||||
CFRelease(Name);
|
||||
Name = CFStringCreateWithBytes(kCFAllocatorDefault, data+pos, c, kCFStringEncodingUTF8, false);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void ColumnField::WriteTypedData(uint8_t *data, size_t len)
|
||||
{
|
||||
int pos = 0;
|
||||
|
||||
CHECK_CHAR(len);
|
||||
PUT_CHAR(MyType); pos++;
|
||||
|
||||
CHECK_CHAR(len);
|
||||
PUT_CHAR(0/*(char)indexUnique*/);
|
||||
pos++;
|
||||
|
||||
if (Name)
|
||||
{
|
||||
CFIndex lengthRequired=0;
|
||||
CFStringGetBytes(Name, CFRangeMake(0, CFStringGetLength(Name)), kCFStringEncodingUTF8, 0, false, NULL, 0, &lengthRequired);
|
||||
CHECK_BIN(len, lengthRequired+1);
|
||||
PUT_CHAR(lengthRequired); pos++;
|
||||
|
||||
CFStringGetBytes(Name, CFRangeMake(0, CFStringGetLength(Name)), kCFStringEncodingUTF8, 0, false, data+pos, lengthRequired, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
PUT_CHAR(0);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
unsigned char ColumnField::GetDataType(void)
|
||||
{
|
||||
return MyType;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void ColumnField::SetDataType(unsigned char type)
|
||||
{
|
||||
if ((MyType == FIELD_INTEGER || MyType == FIELD_BOOLEAN || MyType == FIELD_DATETIME || MyType == FIELD_LENGTH) &&
|
||||
(type == FIELD_INTEGER || type == FIELD_BOOLEAN || type == FIELD_DATETIME || type == FIELD_LENGTH)) {
|
||||
MyType = type;
|
||||
}
|
||||
// going from string to filename or filename to string is OK
|
||||
if ((MyType == FIELD_FILENAME && type == FIELD_STRING)
|
||||
|| (MyType == FIELD_STRING && type == FIELD_FILENAME))
|
||||
{
|
||||
MyType = type;
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
CFStringRef ColumnField::GetFieldName(void)
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
size_t ColumnField::GetDataSize(void)
|
||||
{
|
||||
if (Name)
|
||||
{
|
||||
CFIndex lengthRequired=0;
|
||||
CFStringGetBytes(Name, CFRangeMake(0, CFStringGetLength(Name)), kCFStringEncodingUTF8, 0, false, NULL, 0, &lengthRequired);
|
||||
return lengthRequired+3;
|
||||
}
|
||||
else
|
||||
return 3;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int ColumnField::Compare(Field * /*Entry*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
49
Src/nde/osx/ColumnField.h
Normal file
49
Src/nde/osx/ColumnField.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
ColumnField Class Prototypes
|
||||
Mac OS X implementation
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __COLUMNFIELD_H
|
||||
#define __COLUMNFIELD_H
|
||||
|
||||
#include "Field.h"
|
||||
#include "LinkedList.h"
|
||||
#include "Table.h"
|
||||
|
||||
#include "Scanner.h"
|
||||
|
||||
class ColumnField : public Field
|
||||
{
|
||||
public:
|
||||
ColumnField(unsigned char FieldID, CFStringRef FieldName, unsigned char FieldType, Table *parentTable);
|
||||
ColumnField();
|
||||
~ColumnField();
|
||||
|
||||
/* Field implementation */
|
||||
virtual void ReadTypedData(const uint8_t *, size_t len);
|
||||
virtual void WriteTypedData(uint8_t *, size_t len);
|
||||
virtual size_t GetDataSize(void);
|
||||
virtual int Compare(Field *Entry);
|
||||
|
||||
/* ColumnField methods */
|
||||
void InitField(void);
|
||||
void SetDataType(unsigned char type);
|
||||
bool IsSearchableField() const;
|
||||
void SetSearchable(bool val);
|
||||
unsigned char GetDataType(void);
|
||||
CFStringRef GetFieldName(void);
|
||||
|
||||
protected:
|
||||
bool searchable;
|
||||
CFStringRef Name;
|
||||
unsigned char MyType;
|
||||
};
|
||||
|
||||
#endif
|
45
Src/nde/osx/FilenameField.cpp
Normal file
45
Src/nde/osx/FilenameField.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
#include "FilenameField.h"
|
||||
#include "nde.h"
|
||||
|
||||
/*
|
||||
Mac OS X implementation of FilenameField
|
||||
only the equals operator will be case-sensitive. substring search, ends, starts, etc. will be case-insensitive,
|
||||
to make things like "filename ends .mp3" easier
|
||||
|
||||
TODO: it'd be massive overhead, but it'd be more correct to check if the file system is actually case sensitive (for the path being searched)
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
FilenameField::FilenameField(CFStringRef Str) : StringField(Str)
|
||||
{
|
||||
Type = FIELD_FILENAME;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
FilenameField::FilenameField()
|
||||
{
|
||||
Type = FIELD_FILENAME;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int FilenameField::Compare(Field *Entry)
|
||||
{
|
||||
if (!Entry) return -1;
|
||||
if (Entry->GetType() != GetType()) return 0;
|
||||
|
||||
CFStringRef compareString = ((StringField*)Entry)->GetString();
|
||||
if (!String && !compareString) return 0;
|
||||
if (!String && compareString) return 1;
|
||||
if (!compareString) return -1;
|
||||
|
||||
return CFStringCompare(String, compareString, 0);
|
||||
}
|
||||
|
||||
Field *FilenameField::Clone(Table *pTable)
|
||||
{
|
||||
FilenameField *clone = new FilenameField(String);
|
||||
clone->Pos = FIELD_CLONE;
|
||||
clone->ID = ID;
|
||||
clone->MaxSizeOnDisk = GetDataSize();
|
||||
return clone;
|
||||
}
|
23
Src/nde/osx/FilenameField.h
Normal file
23
Src/nde/osx/FilenameField.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef NDE_FILENAMEFIELD_H
|
||||
#define NDE_FILENAMEFIELD_H
|
||||
|
||||
/*
|
||||
Mostly the same as StringField
|
||||
but this implements OS-dependent string comparisons that make sense for the file system
|
||||
*/
|
||||
|
||||
#include "nde.h"
|
||||
#include "NDEString.h"
|
||||
|
||||
class FilenameField : public StringField
|
||||
{
|
||||
protected:
|
||||
virtual int Compare(Field *Entry);
|
||||
virtual Field *Clone(Table *pTable);
|
||||
|
||||
public:
|
||||
FilenameField(CFStringRef Str);
|
||||
FilenameField();
|
||||
};
|
||||
|
||||
#endif
|
126
Src/nde/osx/IndexField.cpp
Normal file
126
Src/nde/osx/IndexField.cpp
Normal file
|
@ -0,0 +1,126 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
IndexField Class
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "nde.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
IndexField::IndexField(unsigned char id, int Pos, int type, CFStringRef FieldName)
|
||||
{
|
||||
InitField();
|
||||
Type = FIELD_INDEX;
|
||||
Name = (CFStringRef)CFRetain(FieldName);
|
||||
ID = id;
|
||||
Position = Pos;
|
||||
DataType = type;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void IndexField::InitField(void)
|
||||
{
|
||||
index = 0;
|
||||
Type = FIELD_INDEX;
|
||||
Name = NULL;
|
||||
ID = 0;
|
||||
Position = -1;
|
||||
DataType = FIELD_UNKNOWN;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
IndexField::IndexField()
|
||||
{
|
||||
InitField();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
IndexField::~IndexField()
|
||||
{
|
||||
if (Name)
|
||||
CFRelease(Name);
|
||||
delete index;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void IndexField::ReadTypedData(const uint8_t *data, size_t len)
|
||||
{
|
||||
unsigned char c;
|
||||
int pos=0;
|
||||
CHECK_INT(len);
|
||||
Position = GET_INT(); pos += 4;
|
||||
CHECK_INT(len);
|
||||
DataType = GET_INT(); pos += 4;
|
||||
CHECK_CHAR(len);
|
||||
c = GET_CHAR(); pos++;
|
||||
if (c)
|
||||
{
|
||||
CHECK_BIN(len, c);
|
||||
if (Name)
|
||||
CFRelease(Name);
|
||||
Name = CFStringCreateWithBytes(kCFAllocatorDefault, data+pos, c, kCFStringEncodingUTF8, false);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void IndexField::WriteTypedData(uint8_t *data, size_t len)
|
||||
{
|
||||
int pos=0;
|
||||
CHECK_INT(len);
|
||||
PUT_INT(Position); pos += 4;
|
||||
|
||||
CHECK_INT(len);
|
||||
PUT_INT(DataType); pos += 4;
|
||||
CHECK_CHAR(len);
|
||||
|
||||
if (Name)
|
||||
{
|
||||
CFIndex lengthRequired=0;
|
||||
CFStringGetBytes(Name, CFRangeMake(0, CFStringGetLength(Name)), kCFStringEncodingUTF8, 0, false, NULL, 0, &lengthRequired);
|
||||
CHECK_BIN(len, lengthRequired+1);
|
||||
PUT_CHAR(lengthRequired); pos++;
|
||||
|
||||
CFStringGetBytes(Name, CFRangeMake(0, CFStringGetLength(Name)), kCFStringEncodingUTF8, 0, false, data+pos, lengthRequired, 0);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
CFStringRef IndexField::GetIndexName(void)
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
size_t IndexField::GetDataSize(void)
|
||||
{
|
||||
if (Name)
|
||||
{
|
||||
CFIndex lengthRequired=0;
|
||||
CFStringGetBytes(Name, CFRangeMake(0, CFStringGetLength(Name)), kCFStringEncodingUTF8, 0, false, NULL, 0, &lengthRequired);
|
||||
return lengthRequired+9;
|
||||
}
|
||||
else
|
||||
return 9;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int IndexField::Compare(Field * /*Entry*/)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int IndexField::TranslateToIndex(int Id, IndexField *toindex)
|
||||
{
|
||||
if (index && toindex && toindex->index)
|
||||
return index->TranslateIndex(Id, toindex->index);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
37
Src/nde/osx/IndexField.h
Normal file
37
Src/nde/osx/IndexField.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
IndexField Class Prototypes
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __INDEXFIELD_H
|
||||
#define __INDEXFIELD_H
|
||||
|
||||
class IndexField : public Field
|
||||
{
|
||||
public:
|
||||
IndexField(unsigned char id, int Pos, int type, CFStringRef FieldName);
|
||||
IndexField();
|
||||
~IndexField();
|
||||
virtual void ReadTypedData(const uint8_t *, size_t len);
|
||||
virtual void WriteTypedData(uint8_t *, size_t len);
|
||||
virtual size_t GetDataSize(void);
|
||||
virtual int Compare(Field *Entry);
|
||||
void InitField(void);
|
||||
|
||||
CFStringRef GetIndexName(void);
|
||||
int TranslateToIndex(int Id, IndexField *index);
|
||||
Index *index; // TODO: make protected
|
||||
protected:
|
||||
int Position;
|
||||
int DataType;
|
||||
CFStringRef Name;
|
||||
};
|
||||
|
||||
#endif
|
170
Src/nde/osx/IndexRecord.cpp
Normal file
170
Src/nde/osx/IndexRecord.cpp
Normal file
|
@ -0,0 +1,170 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
IndexRecord Class
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "nde.h"
|
||||
#include <stdio.h>
|
||||
|
||||
IndexRecord::IndexRecord(int RecordPos, int insertionPoint, VFILE *TableHandle, Table *ParentTable)
|
||||
{
|
||||
InsertionPoint = insertionPoint;
|
||||
if (RecordPos != 0)
|
||||
{
|
||||
int n=0;
|
||||
uint32_t ThisPos = RecordPos;
|
||||
while (ThisPos)
|
||||
{
|
||||
if (n >= 128)
|
||||
break;
|
||||
Vfseek(TableHandle, ThisPos, SEEK_SET);
|
||||
Field Entry (ThisPos);
|
||||
Field *TypedEntry = Entry.ReadField(ParentTable, ThisPos, &ThisPos);
|
||||
|
||||
if (!TypedEntry) break; // some db error?
|
||||
|
||||
AddField(TypedEntry);
|
||||
// ThisPos = TypedEntry->GetNextFieldPos();
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void IndexRecord::BuildCollaboration()
|
||||
{
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
IndexField *p = (IndexField *)*itr;
|
||||
if (p->next)
|
||||
p->index->Colaborate((IndexField *)p->next);
|
||||
else
|
||||
p->index->Colaborate((IndexField *)*Fields.begin());
|
||||
}
|
||||
}
|
||||
|
||||
bool IndexRecord::NeedFix()
|
||||
{
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
IndexField *p = (IndexField *)*itr;
|
||||
if (p->index->NeedFix())
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
IndexField *IndexRecord::GetIndexByName(const wchar_t *name)
|
||||
{
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
IndexField *p = (IndexField *)*itr;
|
||||
if (!_wcsicmp(p->GetIndexName(), name))
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
IndexField *IndexRecord::GetIndexByName(CFStringRef name)
|
||||
{
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
IndexField *p = (IndexField *)*itr;
|
||||
if (CFStringCompare(p->GetIndexName(), name, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool IndexRecord::CheckIndexing(int v)
|
||||
{
|
||||
int i = v;
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
IndexField *p = (IndexField *)*itr;
|
||||
v = p->index->GetCooperative(v);
|
||||
}
|
||||
return v == i;
|
||||
}
|
||||
|
||||
|
||||
void IndexRecord::SetModified(BOOL modifiedVal)
|
||||
{
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
IndexField *p = (IndexField *)*itr;
|
||||
p->index->Modified = modifiedVal;
|
||||
}
|
||||
}
|
||||
|
||||
Field *RecordBase::GetField(unsigned char ID)
|
||||
{
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
IndexField *p = (IndexField *)*itr;
|
||||
if (p->GetFieldId() == ID)
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void RecordBase::AddField(Field *field)
|
||||
{
|
||||
if (!field) return;
|
||||
if (GetField(field->ID))
|
||||
return;
|
||||
|
||||
Fields.push_back(field);
|
||||
}
|
||||
|
||||
int IndexRecord::WriteFields(Table *ParentTable)
|
||||
{
|
||||
Field *previous = 0;
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
IndexField *p = (IndexField *)*itr;
|
||||
p->WriteField(ParentTable, previous, (Field *)p->next);
|
||||
previous = p;
|
||||
}
|
||||
return WriteIndex(ParentTable);
|
||||
}
|
||||
|
||||
|
||||
int IndexRecord::WriteIndex(Table *ParentTable)
|
||||
{
|
||||
int P=0;
|
||||
if (!Fields.empty())
|
||||
P=(*Fields.begin())->GetFieldPos();
|
||||
return ParentTable->index->Update(INDEX_RECORD_NUM, P, this, FALSE);
|
||||
}
|
||||
|
||||
void RecordBase::RemoveField(Field *field)
|
||||
{
|
||||
if (!field)
|
||||
return;
|
||||
Fields.erase(field);
|
||||
delete field;
|
||||
}
|
||||
|
||||
void IndexRecord::WalkFields(FieldsWalker callback, void *context)
|
||||
{
|
||||
if (callback)
|
||||
{
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
if (!callback(this, *itr, context))
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
19
Src/nde/osx/IndexRecord.h
Normal file
19
Src/nde/osx/IndexRecord.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
#include <stdio.h>
|
||||
#include "Record.h"
|
||||
#include "../nu/PtrDeque2.h"
|
||||
class IndexRecord : public RecordBase
|
||||
{
|
||||
public:
|
||||
IndexRecord(int RecordPos, int insertionPoint, VFILE *FileHandle,Table *p);
|
||||
void BuildCollaboration();
|
||||
bool NeedFix();
|
||||
IndexField *GetIndexByName(const wchar_t *name);
|
||||
int GetColumnCount() { return Fields.size() - 1; }
|
||||
bool CheckIndexing(int v);
|
||||
int WriteFields(Table *ParentTable);
|
||||
int WriteIndex(Table *ParentTable);
|
||||
typedef bool (*FieldsWalker)(IndexRecord *record, Field *entry, void *context);
|
||||
void WalkFields(FieldsWalker callback, void *context);
|
||||
};
|
||||
|
1018
Src/nde/osx/IntegerField.cpp
Normal file
1018
Src/nde/osx/IntegerField.cpp
Normal file
File diff suppressed because it is too large
Load diff
93
Src/nde/osx/IntegerField.h
Normal file
93
Src/nde/osx/IntegerField.h
Normal file
|
@ -0,0 +1,93 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
IntegerField Class Prototypes
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __INTEGERFIELD_H
|
||||
#define __INTEGERFIELD_H
|
||||
|
||||
#include <bfc/platform/types.h>
|
||||
|
||||
class TimeParse {
|
||||
public:
|
||||
int is_relative; // ago/after/before used
|
||||
int absolute_datetime; // if not is_relative, this is the date/time, otherwise it's the resulting date/time if the query was ran now
|
||||
int absolute_hasdate; // if not, use only the time portion of absolute_datetime, the rest is now
|
||||
int absolute_hastime; // if not, use only the date portion of absolute_datetime, the rest is now
|
||||
int relative_year; // -1 = this year
|
||||
int relative_month; // -1 = this month
|
||||
int relative_day; // -1 = this day, -2 = this week
|
||||
int relative_hour; // -1 = this hour
|
||||
int relative_min; // -1 = this minute
|
||||
int relative_sec; // -1 = this second
|
||||
int relative_kwday; // not used(-1), 0 to 6 for sunday to saturday, yesterday(7), today(8), tomorrow(9)
|
||||
int offset_value; // timeago/offsetby numerical edit field
|
||||
int offset_what; // not used(-1) years(0), months(1), weeks(2), days(3), hours(4), minutes(5), seconds(6)
|
||||
int offset_whence; // not used(-1), after(0), ago/before(1)
|
||||
int offset_used; // if 1, 'time ago' / 'offset by' should be checked
|
||||
};
|
||||
|
||||
class IntegerField : public Field
|
||||
{
|
||||
protected:
|
||||
|
||||
virtual void ReadTypedData(const uint8_t *, size_t len);
|
||||
virtual void WriteTypedData(uint8_t *, size_t len);
|
||||
virtual size_t GetDataSize(void);
|
||||
virtual int Compare(Field *Entry);
|
||||
virtual bool ApplyFilter(Field *Data, int op);
|
||||
void InitField(void);
|
||||
int Value;
|
||||
|
||||
enum {
|
||||
WHAT_YEARS,
|
||||
WHAT_MONTHS,
|
||||
WHAT_WEEKS,
|
||||
WHAT_DAYS,
|
||||
WHAT_HOURS,
|
||||
WHAT_MINUTES,
|
||||
WHAT_SECONDS,
|
||||
};
|
||||
|
||||
enum {
|
||||
FROM_BARE,
|
||||
FROM_AGO,
|
||||
FROM_SINCE,
|
||||
};
|
||||
|
||||
public:
|
||||
|
||||
~IntegerField();
|
||||
IntegerField(int);
|
||||
IntegerField();
|
||||
int GetValue(void);
|
||||
void SetValue(int);
|
||||
int ApplyConversion(const char *format, TimeParse *tp=NULL);
|
||||
|
||||
static int LookupToken(CFStringRef t);
|
||||
|
||||
};
|
||||
|
||||
|
||||
class DateTimeField : public IntegerField {
|
||||
public:
|
||||
DateTimeField();
|
||||
DateTimeField(int Val);
|
||||
virtual ~DateTimeField();
|
||||
};
|
||||
|
||||
class LengthField : public IntegerField {
|
||||
public:
|
||||
LengthField();
|
||||
LengthField(int Val);
|
||||
virtual ~LengthField();
|
||||
};
|
||||
|
||||
#endif
|
936
Src/nde/osx/Query.cpp
Normal file
936
Src/nde/osx/Query.cpp
Normal file
|
@ -0,0 +1,936 @@
|
|||
#include "nde.h"
|
||||
#include "NDEString.h"
|
||||
#include "Query.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
BOOL Scanner::Query(const char *query)
|
||||
{
|
||||
if (!query) return FALSE;
|
||||
if (last_query) CFRelease(last_query);
|
||||
last_query = CFStringCreateWithBytes(NULL, (const uint8_t *)query, strlen(query), kCFStringEncodingUTF32, false);
|
||||
RemoveFilters();
|
||||
in_query_parser = 1;
|
||||
BOOL r = Query_Parse(query);
|
||||
|
||||
if (r == FALSE)
|
||||
{
|
||||
if (!disable_date_resolution) RemoveFilters();
|
||||
last_query_failed = TRUE;
|
||||
}
|
||||
in_query_parser = 0;
|
||||
Query_CleanUp();
|
||||
return r & CheckFilters();
|
||||
}
|
||||
|
||||
CFStringRef Scanner::GetLastQuery()
|
||||
{
|
||||
return last_query;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
CFStringRef token;
|
||||
int tid;
|
||||
} tokenstruct;
|
||||
|
||||
tokenstruct Tokens[] = // Feel free to add more...
|
||||
{
|
||||
{CFSTR("AND"), TOKEN_AND },
|
||||
{CFSTR("OR"), TOKEN_OR },
|
||||
{CFSTR("HAS"), TOKEN_CONTAINS },
|
||||
{CFSTR("NOTHAS"),TOKEN_NOTCONTAINS},
|
||||
{CFSTR("BEGINS"), TOKEN_BEGINS },
|
||||
{CFSTR("ENDS"), TOKEN_ENDS },
|
||||
{CFSTR("ISEMPTY"), TOKEN_ISEMPTY},
|
||||
{CFSTR("ISNOTEMPTY"),TOKEN_ISNOTEMPTY},
|
||||
{CFSTR("LIKE"), TOKEN_LIKE},
|
||||
{CFSTR("BEGINSLIKE"), TOKEN_BEGINSLIKE},
|
||||
};
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int Op;
|
||||
int Level;
|
||||
} OpLevel;
|
||||
|
||||
|
||||
static int Query_ParseLength(CFStringRef str)
|
||||
{
|
||||
int x;
|
||||
CFArrayRef array = CFStringCreateArrayBySeparatingStrings(NULL, str, CFSTR(":"));
|
||||
if (array)
|
||||
{
|
||||
CFIndex count = CFArrayGetCount(array);
|
||||
if (count == 2)
|
||||
{
|
||||
CFStringRef t1 = (CFStringRef)CFArrayGetValueAtIndex(array, 0);
|
||||
CFStringRef t2 = (CFStringRef)CFArrayGetValueAtIndex(array, 1);
|
||||
x = CFStringGetIntValue(t1) * 60 + CFStringGetIntValue(t2);
|
||||
CFRelease(array);
|
||||
return x;
|
||||
}
|
||||
|
||||
if (count == 3)
|
||||
{
|
||||
CFStringRef t1 = (CFStringRef)CFArrayGetValueAtIndex(array, 0);
|
||||
CFStringRef t2 = (CFStringRef)CFArrayGetValueAtIndex(array, 1);
|
||||
CFStringRef t3 = (CFStringRef)CFArrayGetValueAtIndex(array, 2);
|
||||
x = CFStringGetIntValue(t1) * 60 * 60 + CFStringGetIntValue(t2) * 60 + CFStringGetIntValue(t3);
|
||||
CFRelease(array);
|
||||
return x;
|
||||
}
|
||||
CFRelease(array);
|
||||
}
|
||||
return CFStringGetIntValue(str);;
|
||||
}
|
||||
|
||||
/*
|
||||
our state machine
|
||||
|
||||
&, |
|
||||
----------<-------------------------<----------------------<-----------
|
||||
| |
|
||||
v ID (Col) =, >, <... ID / Data / [f] ) |
|
||||
---->(0) ----->-----> (1) ------>-----> (2) ------>------> (3) ------>-----> (4) <--
|
||||
| |^ \isempty------------->------------/ |^ | |
|
||||
| !( || ||---- | ) |
|
||||
--<-- ---------<---------------------------<-------------<-| | -->--
|
||||
&, | v [f] |
|
||||
-->--
|
||||
|
||||
*/
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL Scanner::Query_Parse(const char *query)
|
||||
{
|
||||
const char *p = query; // pointer on next token to read
|
||||
size_t size;
|
||||
int state = 0;
|
||||
int pcount = 0;
|
||||
VListEntry<OpLevel> *entry;
|
||||
|
||||
if (pstack.GetNElements() > 0)
|
||||
Query_CleanUp();
|
||||
|
||||
while (1)
|
||||
{
|
||||
p = Query_EatSpace(p);
|
||||
int t = Query_GetNextToken(p, &size, &token);
|
||||
if (t == TOKEN_UNKNOWN)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return FALSE;
|
||||
}
|
||||
if (t == TOKEN_EOQ)
|
||||
break;
|
||||
switch (state)
|
||||
{
|
||||
case 0:
|
||||
switch (t)
|
||||
{
|
||||
case TOKEN_PAROPEN:
|
||||
state = 0;
|
||||
// check too many parenthesis open
|
||||
if (pcount == 255)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query)); // should not be _syntax_ error
|
||||
return FALSE;
|
||||
}
|
||||
// up one level
|
||||
pcount++;
|
||||
break;
|
||||
case TOKEN_NOT:
|
||||
// push not in this level
|
||||
OpLevel o;
|
||||
o.Op = FILTER_NOT;
|
||||
o.Level = pcount;
|
||||
entry = new VListEntry<OpLevel>;
|
||||
entry->SetVal(o);
|
||||
pstack.AddEntry(entry, TRUE);
|
||||
state = 0;
|
||||
break;
|
||||
case TOKEN_IDENTIFIER:
|
||||
state = 1;
|
||||
// create filter column
|
||||
|
||||
if (AddFilterByName(token, NULL, FILTER_NONE) == ADDFILTER_FAILED)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
break;
|
||||
default:
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
switch (t)
|
||||
{
|
||||
case TOKEN_EQUAL:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_EQUALS);
|
||||
break;
|
||||
}
|
||||
case TOKEN_ABOVE:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_ABOVE);
|
||||
break;
|
||||
}
|
||||
case TOKEN_BELOW:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_BELOW);
|
||||
break;
|
||||
}
|
||||
case TOKEN_CONTAINS:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_CONTAINS);
|
||||
break;
|
||||
}
|
||||
case TOKEN_NOTCONTAINS:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_NOTCONTAINS);
|
||||
break;
|
||||
}
|
||||
case TOKEN_AOREQUAL:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_ABOVEOREQUAL);
|
||||
break;
|
||||
}
|
||||
case TOKEN_BOREQUAL:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_BELOWOREQUAL);
|
||||
break;
|
||||
}
|
||||
case TOKEN_NOTEQUAL:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_NOTEQUALS);
|
||||
break;
|
||||
}
|
||||
case TOKEN_BEGINS:
|
||||
{
|
||||
state = 2;
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_BEGINS);
|
||||
}
|
||||
break;
|
||||
case TOKEN_ENDS:
|
||||
{
|
||||
state = 2;
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_ENDS);
|
||||
}
|
||||
break;
|
||||
case TOKEN_LIKE:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_LIKE);
|
||||
break;
|
||||
}
|
||||
case TOKEN_BEGINSLIKE:
|
||||
{
|
||||
state = 2;
|
||||
// set filter op
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(FILTER_BEGINSLIKE);
|
||||
break;
|
||||
}
|
||||
case TOKEN_ISNOTEMPTY:
|
||||
case TOKEN_ISEMPTY:
|
||||
{
|
||||
state = 3;
|
||||
Filter *f = GetLastFilter();
|
||||
f->SetOp(t==TOKEN_ISEMPTY ? FILTER_ISEMPTY : FILTER_ISNOTEMPTY);
|
||||
// pop all operators in this level beginning by the last inserted
|
||||
entry = (VListEntry<OpLevel> *)pstack.GetFoot();
|
||||
while (entry)
|
||||
{
|
||||
if (entry->GetVal().Level == pcount)
|
||||
{
|
||||
AddFilterOp(entry->GetVal().Op);
|
||||
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
|
||||
pstack.RemoveEntry(entry);
|
||||
entry = _entry;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (t == TOKEN_SQBRACKETOPEN)
|
||||
{
|
||||
state = 3;
|
||||
const char *s = strchr(p, ']');
|
||||
if (!s)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return FALSE;
|
||||
}
|
||||
p = Query_EatSpace(p);
|
||||
if (*p == '[') p++;
|
||||
|
||||
CFStringRef format = CFStringCreateWithBytes(NULL, (const uint8_t *)p, (s-p), kCFStringEncodingUTF32, false);
|
||||
Filter *f = GetLastFilter();
|
||||
int id = f->GetId();
|
||||
ColumnField *c = GetColumnById(id);
|
||||
int tt = c ? c->GetDataType() : -1;
|
||||
if (disable_date_resolution || !c || (tt != FIELD_INTEGER && tt != FIELD_DATETIME && tt != FIELD_LENGTH && tt != FIELD_BOOLEAN))
|
||||
{
|
||||
|
||||
if (disable_date_resolution)
|
||||
{
|
||||
StringField *field = (StringField *)f->Data();
|
||||
|
||||
if (!field)
|
||||
{
|
||||
// format was used without a value, assume value is 0
|
||||
f->SetData(new StringField(CFSTR("")));
|
||||
entry = (VListEntry<OpLevel> *)pstack.GetFoot();
|
||||
while (entry)
|
||||
{
|
||||
if (entry->GetVal().Level == pcount)
|
||||
{
|
||||
AddFilterOp(entry->GetVal().Op);
|
||||
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
|
||||
pstack.RemoveEntry(entry);
|
||||
entry = _entry;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
field = (StringField*)f->Data();
|
||||
}
|
||||
|
||||
field->SetNDEString(format);
|
||||
if (format) CFRelease(format);
|
||||
p = s+1;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (format) CFRelease(format);
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
IntegerField *field = (IntegerField *)f->Data();
|
||||
|
||||
if (!field)
|
||||
{
|
||||
// format was used without a value, assume value is 0
|
||||
f->SetData(new IntegerField(0));
|
||||
entry = (VListEntry<OpLevel> *)pstack.GetFoot();
|
||||
while (entry)
|
||||
{
|
||||
if (entry->GetVal().Level == pcount)
|
||||
{
|
||||
AddFilterOp(entry->GetVal().Op);
|
||||
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
|
||||
pstack.RemoveEntry(entry);
|
||||
entry = _entry;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
field = (IntegerField *)f->Data();
|
||||
}
|
||||
|
||||
// TODO: make sure this is safe (that p and s havn't been iterated)
|
||||
char *temp_format = (char *)malloc((s-p+1));
|
||||
strncpy(temp_format, p, s-p);
|
||||
temp_format[s-p] = 0;
|
||||
int r = field->ApplyConversion(temp_format);
|
||||
free(temp_format);
|
||||
|
||||
ndestring_release(format);
|
||||
if (!r)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return FALSE;
|
||||
}
|
||||
p = s+1;
|
||||
continue;
|
||||
}
|
||||
// switch (t) {
|
||||
// case TOKEN_IDENTIFIER:
|
||||
else // JF> we make this relaxed, so anything is valid as a value
|
||||
{
|
||||
state = 3;
|
||||
// set filter data
|
||||
Filter *f = GetLastFilter();
|
||||
int id = f->GetId();
|
||||
ColumnField *c = GetColumnById(id);
|
||||
switch (c ? c->GetDataType() : -1)
|
||||
{
|
||||
case FIELD_DATETIME:
|
||||
if (disable_date_resolution)
|
||||
goto field_string_override;
|
||||
case FIELD_LENGTH:
|
||||
{
|
||||
int i;
|
||||
IntegerField *i_f = new IntegerField();
|
||||
i = Query_ParseLength(token);
|
||||
i_f->SetValue(i);
|
||||
f->SetData(i_f);
|
||||
}
|
||||
break;
|
||||
|
||||
case FIELD_BOOLEAN:
|
||||
case FIELD_INTEGER:
|
||||
{
|
||||
int i;
|
||||
IntegerField *i_f = new IntegerField();
|
||||
i = CFStringGetIntValue(token);
|
||||
i_f->SetValue(i);
|
||||
f->SetData(i_f);
|
||||
}
|
||||
break;
|
||||
case FIELD_INT64:
|
||||
{
|
||||
int64_t i;
|
||||
Int64Field *i_f = new Int64Field();
|
||||
#ifdef _WIN32
|
||||
i = _wtoi64(token); // todo: Replace with own conversion and error checking
|
||||
#else
|
||||
i = CFStringGetIntValue(token); // TODO!!! 64bit integer here ... maybe use CFNumberFormatterCreateNumberFromString but it's a lot of overhead
|
||||
#endif
|
||||
i_f->SetValue(i);
|
||||
f->SetData(i_f);
|
||||
}
|
||||
break;
|
||||
case FIELD_FILENAME:
|
||||
{
|
||||
FilenameField *s_f = new FilenameField();
|
||||
s_f->SetNDEString(token);
|
||||
f->SetData(s_f);
|
||||
}
|
||||
break;
|
||||
case FIELD_STRING:
|
||||
field_string_override:
|
||||
{
|
||||
StringField *s_f = new StringField();
|
||||
s_f->SetNDEString(token);
|
||||
f->SetData(s_f);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return FALSE;
|
||||
break;
|
||||
|
||||
}
|
||||
// pop all operators in this level beginning by the last inserted
|
||||
entry = (VListEntry<OpLevel> *)pstack.GetFoot();
|
||||
while (entry)
|
||||
{
|
||||
if (entry->GetVal().Level == pcount)
|
||||
{
|
||||
AddFilterOp(entry->GetVal().Op);
|
||||
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
|
||||
pstack.RemoveEntry(entry);
|
||||
entry = _entry;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// default:
|
||||
// Query_SyntaxError(p-query);
|
||||
// return FALSE;
|
||||
// }
|
||||
break;
|
||||
case 3:
|
||||
switch (t)
|
||||
{
|
||||
case TOKEN_SQBRACKETOPEN:
|
||||
{
|
||||
const char *s = strchr(p, ']');
|
||||
if (!s)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return FALSE;
|
||||
}
|
||||
p = Query_EatSpace(p);
|
||||
if (*p == '[') p++;
|
||||
CFStringRef format = CFStringCreateWithBytes(NULL, (const uint8_t *)p, (s-p), kCFStringEncodingUTF32, false);
|
||||
Filter *f = GetLastFilter();
|
||||
int id = f->GetId();
|
||||
ColumnField *c = GetColumnById(id);
|
||||
int tt = c ? c->GetDataType() : -1;
|
||||
if (disable_date_resolution || !c || (tt != FIELD_INTEGER && tt != FIELD_DATETIME && tt != FIELD_LENGTH && tt != FIELD_BOOLEAN))
|
||||
{
|
||||
if (disable_date_resolution)
|
||||
{
|
||||
StringField *field = (StringField *)f->Data();
|
||||
|
||||
if (!field)
|
||||
{
|
||||
// format was used without a value, assume value is 0
|
||||
f->SetData(new StringField(CFSTR("")));
|
||||
entry = (VListEntry<OpLevel> *)pstack.GetFoot();
|
||||
while (entry)
|
||||
{
|
||||
if (entry->GetVal().Level == pcount)
|
||||
{
|
||||
AddFilterOp(entry->GetVal().Op);
|
||||
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
|
||||
pstack.RemoveEntry(entry);
|
||||
entry = _entry;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
field = (StringField *)f->Data();
|
||||
}
|
||||
|
||||
field->SetNDEString(format);
|
||||
if (format) CFRelease(format);
|
||||
p = s+1;
|
||||
continue;
|
||||
}
|
||||
if (format) CFRelease(format);
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
IntegerField *field = (IntegerField *)f->Data();
|
||||
|
||||
if (!field)
|
||||
{
|
||||
// format was used without a value, assume value is 0
|
||||
f->SetData(new IntegerField(0));
|
||||
entry = (VListEntry<OpLevel> *)pstack.GetFoot();
|
||||
while (entry)
|
||||
{
|
||||
if (entry->GetVal().Level == pcount)
|
||||
{
|
||||
AddFilterOp(entry->GetVal().Op);
|
||||
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
|
||||
pstack.RemoveEntry(entry);
|
||||
entry = _entry;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
field = (IntegerField *)f->Data();
|
||||
}
|
||||
|
||||
// TODO: make sure this is safe (that p and s havn't been iterated)
|
||||
char *temp_format = (char *)malloc((s-p+1));
|
||||
strncpy(temp_format, p, s-p);
|
||||
temp_format[s-p] = 0;
|
||||
int r = field->ApplyConversion(temp_format);
|
||||
free(temp_format);
|
||||
|
||||
ndestring_release(format);
|
||||
if (!r)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return FALSE;
|
||||
}
|
||||
p = s+1;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
|
||||
case TOKEN_PARCLOSE:
|
||||
state = 4;
|
||||
// check parenthesis count
|
||||
if (pcount == 0)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return FALSE;
|
||||
}
|
||||
// down one level
|
||||
pcount--;
|
||||
// pop all operators in this level, beginning by the last inserted
|
||||
while (entry)
|
||||
{
|
||||
if (entry->GetVal().Level == pcount)
|
||||
{
|
||||
AddFilterOp(entry->GetVal().Op);
|
||||
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
|
||||
pstack.RemoveEntry(entry);
|
||||
entry = _entry;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case TOKEN_AND:
|
||||
{
|
||||
state = 0;
|
||||
// push and
|
||||
OpLevel o;
|
||||
o.Op = FILTER_AND;
|
||||
o.Level = pcount;
|
||||
entry = new VListEntry<OpLevel>;
|
||||
entry->SetVal(o);
|
||||
pstack.AddEntry(entry, TRUE);
|
||||
break;
|
||||
}
|
||||
case TOKEN_OR:
|
||||
{
|
||||
state = 0;
|
||||
// push or
|
||||
OpLevel o;
|
||||
o.Op = FILTER_OR;
|
||||
o.Level = pcount;
|
||||
entry = new VListEntry<OpLevel>;
|
||||
entry->SetVal(o);
|
||||
pstack.AddEntry(entry, TRUE);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
switch (t)
|
||||
{
|
||||
case TOKEN_AND:
|
||||
{
|
||||
state = 0;
|
||||
// push and
|
||||
OpLevel o;
|
||||
o.Op = FILTER_AND;
|
||||
o.Level = pcount;
|
||||
entry = new VListEntry<OpLevel>;
|
||||
entry->SetVal(o);
|
||||
pstack.AddEntry(entry, TRUE);
|
||||
break;
|
||||
}
|
||||
case TOKEN_OR:
|
||||
{
|
||||
state = 0;
|
||||
// push or
|
||||
OpLevel o;
|
||||
o.Op = FILTER_OR;
|
||||
o.Level = pcount;
|
||||
entry = new VListEntry<OpLevel>;
|
||||
entry->SetVal(o);
|
||||
pstack.AddEntry(entry, TRUE);
|
||||
break;
|
||||
}
|
||||
case TOKEN_PARCLOSE:
|
||||
state = 4;
|
||||
// check parenthesis count
|
||||
if (pcount == 0)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return FALSE;
|
||||
}
|
||||
// down one level
|
||||
pcount--;
|
||||
// pop all operators in this level, beginning by the last inserted
|
||||
while (entry)
|
||||
{
|
||||
if (entry->GetVal().Level == pcount)
|
||||
{
|
||||
AddFilterOp(entry->GetVal().Op);
|
||||
VListEntry<OpLevel> *_entry = (VListEntry<OpLevel> *)entry->GetPrevious();
|
||||
pstack.RemoveEntry(entry);
|
||||
entry = _entry;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Ahem... :/
|
||||
break;
|
||||
}
|
||||
p += size;
|
||||
}
|
||||
if (pcount > 0)
|
||||
{
|
||||
Query_SyntaxError((int)(p-query));
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
||||
void Scanner::Query_SyntaxError(int c)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Scanner::Query_CleanUp()
|
||||
{
|
||||
while (pstack.GetNElements() > 0)
|
||||
{
|
||||
VListEntry<int> *e;
|
||||
e = (VListEntry<int> *)pstack.GetHead();
|
||||
pstack.RemoveEntry(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
const char *Scanner::Query_EatSpace(const char *p)
|
||||
{
|
||||
while (*p && *p == ' ') p++;
|
||||
return p;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
const char *Scanner::Query_ProbeNonAlphaNum(const char *p)
|
||||
{
|
||||
int inquote=0;
|
||||
while (*p && (!Query_isControlChar(*p) || (inquote)))
|
||||
{
|
||||
if (*p == '\"')
|
||||
{
|
||||
if (!inquote)
|
||||
inquote = 1;
|
||||
else
|
||||
return p+1;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Scanner::Query_isControlChar(char p)
|
||||
{
|
||||
switch (p)
|
||||
{
|
||||
case '&':
|
||||
case '|':
|
||||
case '!':
|
||||
case '(':
|
||||
case '[':
|
||||
case ')':
|
||||
case ']':
|
||||
case '>':
|
||||
case '<':
|
||||
case '=':
|
||||
case ',':
|
||||
case ' ':
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
char *Scanner::Query_ProbeAlphaNum(char *p)
|
||||
{
|
||||
while (*p && Query_isControlChar(*p)) p++;
|
||||
return p;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
char *Scanner::Query_ProbeSpace(char *p)
|
||||
{
|
||||
while (*p && *p != ' ') p++;
|
||||
return p;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Scanner::Query_LookupToken(CFStringRef t)
|
||||
{
|
||||
for (int i=0;i<sizeof(Tokens)/sizeof(tokenstruct);i++)
|
||||
{
|
||||
if (CFStringCompare(Tokens[i].token, t, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
|
||||
return Tokens[i].tid;
|
||||
}
|
||||
return TOKEN_IDENTIFIER;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Scanner::Query_GetNextToken(const char *p, size_t *size, CFStringRef *_token, int tokentable)
|
||||
{
|
||||
|
||||
int t = TOKEN_EOQ;
|
||||
const char *startptr = p;
|
||||
|
||||
if (!*p) return TOKEN_EOQ;
|
||||
|
||||
p = Query_EatSpace(p);
|
||||
|
||||
const char *e = Query_ProbeNonAlphaNum(p);
|
||||
|
||||
if (e != p) // We have a word
|
||||
{
|
||||
if (*_token) CFRelease(*_token);
|
||||
|
||||
// check for a quoted string
|
||||
if (*p == '\"' && e != p+1 && e[-1] == '\"')
|
||||
{
|
||||
CFStringRef inner_string = CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)(p+1), (e-p-2), kCFStringEncodingUTF8, false);
|
||||
|
||||
// escape it (ugh)
|
||||
CFStringRef escaped_string = CFURLCreateStringByReplacingPercentEscapes(NULL, inner_string, CFSTR(""));
|
||||
if (escaped_string)
|
||||
{
|
||||
*_token = escaped_string;
|
||||
CFRelease(inner_string);
|
||||
}
|
||||
else
|
||||
{
|
||||
*_token = inner_string;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*_token = CFStringCreateWithBytes(kCFAllocatorDefault, (const UInt8 *)p, (e-p), kCFStringEncodingUTF8, false);
|
||||
}
|
||||
|
||||
switch (tokentable)
|
||||
{
|
||||
case -1:
|
||||
t = TOKEN_IDENTIFIER;
|
||||
break;
|
||||
case 0:
|
||||
t = Query_LookupToken(*_token);
|
||||
break;
|
||||
case 1:
|
||||
t = IntegerField::LookupToken(*_token);
|
||||
}
|
||||
p = e;
|
||||
}
|
||||
else // We have a symbol
|
||||
{
|
||||
switch (*p)
|
||||
{
|
||||
case '&':
|
||||
if (*(p+1) == '&') p++;
|
||||
t = TOKEN_AND;
|
||||
break;
|
||||
case '|':
|
||||
if (*(p+1) == '|') p++;
|
||||
t = TOKEN_OR;
|
||||
break;
|
||||
case '!':
|
||||
if (*(p+1) == '=')
|
||||
{
|
||||
p++;
|
||||
t = TOKEN_NOTEQUAL;
|
||||
break;
|
||||
}
|
||||
t = TOKEN_NOT;
|
||||
break;
|
||||
case '(':
|
||||
t = TOKEN_PAROPEN;
|
||||
break;
|
||||
case ')':
|
||||
t = TOKEN_PARCLOSE;
|
||||
break;
|
||||
case '[':
|
||||
t = TOKEN_SQBRACKETOPEN;
|
||||
break;
|
||||
case ']':
|
||||
t = TOKEN_SQBRACKETCLOSE;
|
||||
break;
|
||||
case ',':
|
||||
t = TOKEN_COMMA;
|
||||
break;
|
||||
case '>':
|
||||
if (*(p+1) == '=')
|
||||
{
|
||||
p++;
|
||||
t = TOKEN_AOREQUAL;
|
||||
break;
|
||||
}
|
||||
if (*(p+1) == '<')
|
||||
{
|
||||
p++;
|
||||
t = TOKEN_NOTEQUAL;
|
||||
break;
|
||||
}
|
||||
t = TOKEN_ABOVE;
|
||||
break;
|
||||
case '<':
|
||||
if (*(p+1) == '=')
|
||||
{
|
||||
p++;
|
||||
t = TOKEN_BOREQUAL;
|
||||
break;
|
||||
}
|
||||
if (*(p+1) == '>')
|
||||
{
|
||||
p++;
|
||||
t = TOKEN_NOTEQUAL;
|
||||
break;
|
||||
}
|
||||
t = TOKEN_BELOW;
|
||||
break;
|
||||
case '=':
|
||||
if (*(p+1) == '>')
|
||||
{
|
||||
p++;
|
||||
t = TOKEN_AOREQUAL;
|
||||
break;
|
||||
}
|
||||
if (*(p+1) == '<')
|
||||
{
|
||||
p++;
|
||||
t = TOKEN_BOREQUAL;
|
||||
break;
|
||||
}
|
||||
if (*(p+1) == '!')
|
||||
{
|
||||
p++;
|
||||
t = TOKEN_NOTEQUAL;
|
||||
break;
|
||||
}
|
||||
if (*(p+1) == '=') p++;
|
||||
t = TOKEN_EQUAL;
|
||||
break;
|
||||
default:
|
||||
t = TOKEN_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
}
|
||||
|
||||
*size = (int)(p - startptr);
|
||||
return t;
|
||||
}
|
||||
|
27
Src/nde/osx/Query.h
Normal file
27
Src/nde/osx/Query.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
|
||||
#define TOKEN_UNKNOWN -1 // BLAAAAA!!!!!!!!
|
||||
#define TOKEN_EOQ 0 // End of Query
|
||||
#define TOKEN_IDENTIFIER 1 // Column name or data to match against
|
||||
#define TOKEN_EQUAL 2 // =, ==, IS
|
||||
#define TOKEN_NOTEQUAL 3 // !=, =!, <>, ><
|
||||
#define TOKEN_BELOW 4 // <
|
||||
#define TOKEN_ABOVE 5 // >
|
||||
#define TOKEN_BOREQUAL 6 // <=, =<
|
||||
#define TOKEN_AOREQUAL 7 // >=, =>
|
||||
#define TOKEN_NOT 8 // !, NOT
|
||||
#define TOKEN_AND 9 // &, &&, AND
|
||||
#define TOKEN_OR 10 // |, ||, OR
|
||||
#define TOKEN_PAROPEN 11 // (
|
||||
#define TOKEN_PARCLOSE 12 // )
|
||||
#define TOKEN_CONTAINS 13 // HAS
|
||||
#define TOKEN_BEGINS 14 // string starts with...
|
||||
#define TOKEN_ENDS 15 // string ends with...
|
||||
#define TOKEN_LIKE 16 // string is nearly (excluding "the " and whitespace etc)
|
||||
#define TOKEN_ISEMPTY 17 // field does not exists
|
||||
#define TOKEN_SQBRACKETOPEN 18 // [
|
||||
#define TOKEN_SQBRACKETCLOSE 19 // ]
|
||||
#define TOKEN_COMMA 20 // ,
|
||||
#define TOKEN_NOTCONTAINS 21 // NOTHAS
|
||||
#define TOKEN_ISNOTEMPTY 22 // field does not exists
|
||||
#define TOKEN_BEGINSLIKE 23 // string is nearly starts with (excluding "the " and whitespace etc)
|
138
Src/nde/osx/Record.cpp
Normal file
138
Src/nde/osx/Record.cpp
Normal file
|
@ -0,0 +1,138 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Record Class
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
//#include "record.h"
|
||||
#include "nde.h"
|
||||
#include <stdio.h>
|
||||
|
||||
void RecordBase::Retain()
|
||||
{
|
||||
ref_count++;
|
||||
}
|
||||
|
||||
void RecordBase::Release()
|
||||
{
|
||||
if (--ref_count == 0)
|
||||
delete this;
|
||||
}
|
||||
|
||||
RecordBase::RecordBase()
|
||||
{
|
||||
ref_count = 1;
|
||||
InsertionPoint = 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Record::Record(int RecordPos, int insertionPoint, VFILE *TableHandle, Table *ParentTable)
|
||||
{
|
||||
InsertionPoint = insertionPoint;
|
||||
Record *columns = ParentTable->GetColumns();
|
||||
int max=columns ? columns->Fields.size() : 128;
|
||||
int n=0;
|
||||
if (RecordPos != 0)
|
||||
{
|
||||
uint32_t ThisPos = RecordPos;
|
||||
while (ThisPos)
|
||||
{
|
||||
if (n >= max)
|
||||
break;
|
||||
Vfseek(TableHandle, ThisPos, SEEK_SET);
|
||||
Field Entry (ThisPos);
|
||||
Field *TypedEntry = Entry.ReadField(ParentTable, ThisPos, &ThisPos);
|
||||
|
||||
if (!TypedEntry) break; // some db error?
|
||||
|
||||
AddField(TypedEntry);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
RecordBase::~RecordBase()
|
||||
{
|
||||
Fields.deleteAll();
|
||||
}
|
||||
|
||||
|
||||
#ifdef _WIN32
|
||||
ColumnField *Record::GetColumnByName(const wchar_t *name)
|
||||
{
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
ColumnField *p = (ColumnField *)*itr;
|
||||
if (!_wcsicmp(p->GetFieldName(), name))
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
ColumnField *Record::GetColumnByName(CFStringRef name)
|
||||
{
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
ColumnField *p = (ColumnField *)*itr;
|
||||
if (CFStringCompare(p->GetFieldName(), name, kCFCompareCaseInsensitive) == kCFCompareEqualTo)
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Record::WriteFields(Table *ParentTable, int RecordIndex)
|
||||
{
|
||||
Field *previous = 0;
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
Field *p = *itr;
|
||||
p->WriteField(ParentTable, previous, (Field *)p->next);
|
||||
previous = p;
|
||||
}
|
||||
return WriteIndex(ParentTable, RecordIndex);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int Record::WriteIndex(Table *ParentTable, int RecordIndex)
|
||||
{
|
||||
int P=0;
|
||||
if (RecordIndex == NEW_RECORD)
|
||||
RecordIndex = ParentTable->index->Insert(InsertionPoint);
|
||||
if (!Fields.empty())
|
||||
{
|
||||
Field *f = *Fields.begin();
|
||||
P=f->GetFieldPos();
|
||||
}
|
||||
return ParentTable->index->Update(RecordIndex, P, this, FALSE);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Record::Delete(Table *ParentTable, int RecordIndex)
|
||||
{
|
||||
ParentTable->index->Delete(RecordIndex, ParentTable->index->Get(RecordIndex), this);
|
||||
}
|
||||
|
||||
void Record::WalkFields(FieldsWalker callback, void *context)
|
||||
{
|
||||
if (callback)
|
||||
{
|
||||
for (FieldList::iterator itr=Fields.begin();itr!=Fields.end();itr++)
|
||||
{
|
||||
if (!callback(this, *itr, context))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
50
Src/nde/osx/Record.h
Normal file
50
Src/nde/osx/Record.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
#pragma once
|
||||
|
||||
#include "field.h"
|
||||
#include "Vfs.h"
|
||||
#include <stdio.h>
|
||||
#include "../nu/PtrMap.h"
|
||||
#ifdef __APPLE__
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
class ColumnField;
|
||||
|
||||
class RecordBase
|
||||
{
|
||||
public:
|
||||
RecordBase();
|
||||
virtual ~RecordBase();
|
||||
Field *GetField(unsigned char ID);
|
||||
void Retain();
|
||||
void Release();
|
||||
void RemoveField(Field *field);
|
||||
void AddField(Field *field);
|
||||
|
||||
protected:
|
||||
void Undelete(void);
|
||||
|
||||
int InsertionPoint; // TODO: benski> might be able to pass this into WriteFields/WriteIndex
|
||||
int ref_count;
|
||||
typedef nu::PtrDeque2<Field> FieldList;
|
||||
FieldList Fields;
|
||||
};
|
||||
|
||||
|
||||
class Record : public RecordBase
|
||||
{
|
||||
public:
|
||||
Record(int RecordPos, int insertionPoint, VFILE *FileHandle,Table *p);
|
||||
bool InCache() { return ref_count > 1; }
|
||||
|
||||
#ifdef __APPLE__
|
||||
ColumnField *GetColumnByName(CFStringRef name);
|
||||
#else
|
||||
ColumnField *GetColumnByName(const wchar_t *name);
|
||||
#endif
|
||||
int WriteFields(Table *ParentTable, int RecordIndex);
|
||||
int WriteIndex(Table *ParentTable, int RecordIndex);
|
||||
void Delete(Table *ParentTable, int RecordIndex);
|
||||
typedef bool (*FieldsWalker)(Record *record, Field *entry, void *context);
|
||||
NDE_API void WalkFields(FieldsWalker callback, void *context);
|
||||
};
|
||||
|
1283
Src/nde/osx/Scanner.cpp
Normal file
1283
Src/nde/osx/Scanner.cpp
Normal file
File diff suppressed because it is too large
Load diff
210
Src/nde/osx/Scanner.h
Normal file
210
Src/nde/osx/Scanner.h
Normal file
|
@ -0,0 +1,210 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Scanner Class Prototypes
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __SCANNER_H
|
||||
#define __SCANNER_H
|
||||
|
||||
#include "record.h"
|
||||
#include "Table.h"
|
||||
#include "index.h"
|
||||
#include "../nu/Vector.h"
|
||||
#include "../nu/ValueSet.h"
|
||||
#ifdef __APPLE__
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
class Table;
|
||||
class Index;
|
||||
#pragma warning( disable: 4251 )
|
||||
class Scanner;
|
||||
class Record;
|
||||
class Scanner : public LinkedListEntry
|
||||
{
|
||||
public:
|
||||
Record *GetRecord(int Idx);
|
||||
Scanner(Table *parentTable);
|
||||
void IndexModified(void);
|
||||
Index *GetIndex() { return index; }
|
||||
Index *index; // TODO: make protected
|
||||
|
||||
protected:
|
||||
~Scanner();
|
||||
|
||||
Table *pTable;
|
||||
BOOL iModified;
|
||||
typedef Vector<StringField *> SearchStrings;
|
||||
SearchStrings search_strings;
|
||||
typedef ValueSet<unsigned char> SearchFields;
|
||||
SearchFields search_fields;
|
||||
bool search_any;
|
||||
|
||||
void GetCurrentRecord(void);
|
||||
bool MatchFilters(void);
|
||||
bool MatchSearches();
|
||||
bool MatchSearch(const SearchFields &fields, StringField *search_field);
|
||||
//BOOL MatchJoins(void);
|
||||
int CheckFilters(void);
|
||||
void CacheLastLocate(int Id, int From, Field *field, Index *i, int j);
|
||||
|
||||
#ifdef _WIN32
|
||||
static int Query_LookupToken(const wchar_t *token);
|
||||
#else
|
||||
static int Query_LookupToken(CFStringRef token);
|
||||
#endif
|
||||
void Query_CleanUp(void);
|
||||
void Query_SyntaxError(int c);
|
||||
public:
|
||||
#ifdef _WIN32
|
||||
static int Query_GetNextToken(const wchar_t *p, int *size, wchar_t **token, int tokentable=0);
|
||||
static const wchar_t *Query_EatSpace(const wchar_t *p);
|
||||
static wchar_t *Query_ProbeSpace(wchar_t *p);
|
||||
static const wchar_t *Query_ProbeNonAlphaNum(const wchar_t *p);
|
||||
static wchar_t *Query_ProbeAlphaNum(wchar_t *p);
|
||||
static int Query_isControlChar(wchar_t p);
|
||||
|
||||
BOOL Query(const wchar_t *query);
|
||||
BOOL Query_Parse(const wchar_t *query);
|
||||
#else
|
||||
static int Query_GetNextToken(const char *p, size_t *size, CFStringRef *token, int tokentable=0);
|
||||
static const char *Query_EatSpace(const char *p);
|
||||
static char *Query_ProbeSpace(char *p);
|
||||
static const char *Query_ProbeNonAlphaNum(const char *p);
|
||||
static char *Query_ProbeAlphaNum(char *p);
|
||||
static int Query_isControlChar(char p);
|
||||
|
||||
BOOL Query(const char *query);
|
||||
BOOL Query_Parse(const char *query);
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
const wchar_t *GetLastQuery();
|
||||
#elif defined(__APPLE__)
|
||||
CFStringRef GetLastQuery();
|
||||
#endif
|
||||
|
||||
public://fucko: protected
|
||||
//String token;
|
||||
LinkedList pstack;
|
||||
#ifdef _WIN32
|
||||
wchar_t *token;
|
||||
#else
|
||||
CFStringRef token;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
wchar_t *last_query;
|
||||
#elif defined(__APPLE__)
|
||||
CFStringRef last_query;
|
||||
#endif
|
||||
int last_query_failed;
|
||||
|
||||
protected:
|
||||
Record *CurrentRecord;
|
||||
int CurrentRecordIdx;
|
||||
LinkedList FilterList;
|
||||
Index *lastLocateIndex;
|
||||
int lastLocateIdx;
|
||||
Field *lastLocateFieldClone;
|
||||
int lastLocateFrom;
|
||||
int lastLocateId;
|
||||
BOOL Edition;
|
||||
int ResultPtr;
|
||||
BOOL FiltersOK;
|
||||
|
||||
public:
|
||||
bool MatchFilter(Filter *filter);
|
||||
typedef bool (*FilterWalker)(Scanner *scanner, Filter *filter, void *context);
|
||||
void WalkFilters(FilterWalker walker, void *context);
|
||||
|
||||
#ifdef _WIN32
|
||||
ColumnField *GetColumnByName(const wchar_t *FieldName);
|
||||
#else
|
||||
ColumnField *GetColumnByName(CFStringRef FieldName);
|
||||
#endif
|
||||
ColumnField *GetColumnById(unsigned char id);
|
||||
|
||||
#ifdef _WIN32
|
||||
Field *NewFieldByName(const wchar_t *fieldName, unsigned char Perm);
|
||||
#else
|
||||
Field *NewFieldByName(CFStringRef fieldName, unsigned char Perm);
|
||||
#endif
|
||||
Field *NewFieldById(unsigned char Id, unsigned char Perm);
|
||||
void DeleteField(Field *field);
|
||||
#ifdef _WIN32
|
||||
void DeleteFieldByName(const wchar_t *name);
|
||||
#else
|
||||
void DeleteFieldByName(CFStringRef name);
|
||||
#endif
|
||||
void DeleteFieldById(unsigned char Id);
|
||||
|
||||
void Cancel(void);
|
||||
void Insert(void);
|
||||
void Edit(void);
|
||||
void Post(void);
|
||||
void Delete(void);
|
||||
|
||||
#ifdef _WIN32
|
||||
Field *GetFieldByName(const wchar_t *FieldName);
|
||||
#else
|
||||
Field *GetFieldByName(CFStringRef FieldName);
|
||||
#endif
|
||||
Field *GetFieldById(unsigned char Id);
|
||||
|
||||
void First(int *killswitch=0);
|
||||
void Last(int *killswitch=0);
|
||||
int Next(int *killswitch=0);
|
||||
int Previous(int *killswitch=0);
|
||||
BOOL Eof(void);
|
||||
BOOL Bof(void);
|
||||
void New(void);
|
||||
int GetRecordsCount(void);
|
||||
void GetRecordById(int Id, BOOL checkFilters=TRUE);
|
||||
int GetRecordId(void);
|
||||
void Sync(void);
|
||||
#ifdef _WIN32
|
||||
BOOL LocateByName(const wchar_t *column, int From, Field *field, int *nskip=NULL);
|
||||
#else
|
||||
BOOL LocateByName(CFStringRef column, int From, Field *field, int *nskip=NULL);
|
||||
#endif
|
||||
BOOL LocateById(int Id, int From, Field *field, int *nskip=NULL);
|
||||
BOOL LocateByIdEx(int Id, int From, Field *field, int *nskip, int comp_mode);
|
||||
|
||||
// Filters
|
||||
#ifdef _WIN32
|
||||
int AddFilterByName(const wchar_t *name, Field *Data, unsigned char Op);
|
||||
#else
|
||||
int AddFilterByName(CFStringRef name, Field *Data, unsigned char Op);
|
||||
#endif
|
||||
int AddFilterById(unsigned char Id, Field *Data, unsigned char Op);
|
||||
int AddFilterOp(unsigned char Op);
|
||||
void RemoveFilters(void);
|
||||
Filter *GetLastFilter(void);
|
||||
|
||||
#ifdef _WIN32
|
||||
BOOL SetWorkingIndexByName(const wchar_t *desc);
|
||||
#else
|
||||
BOOL SetWorkingIndexByName(CFStringRef desc);
|
||||
#endif
|
||||
BOOL SetWorkingIndexById(unsigned char Id);
|
||||
|
||||
#ifdef _WIN32
|
||||
void Search(const wchar_t *search_string);
|
||||
#endif
|
||||
BOOL HasIndexChanged(void) { return iModified; }
|
||||
void ClearDirtyBit(void);
|
||||
float FragmentationLevel(void);
|
||||
|
||||
Table *GetTable();
|
||||
int in_query_parser;
|
||||
int disable_date_resolution;
|
||||
};
|
||||
|
||||
#endif
|
297
Src/nde/osx/StringField.cpp
Normal file
297
Src/nde/osx/StringField.cpp
Normal file
|
@ -0,0 +1,297 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
StringField Class
|
||||
|
||||
Mac OS X (CFStringRef) implementation
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#include "../nde.h"
|
||||
#include "StringField.h"
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
StringField::StringField(CFStringRef Str)
|
||||
{
|
||||
InitField();
|
||||
Type = FIELD_STRING;
|
||||
if (Str)
|
||||
{
|
||||
SetNDEString(Str);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void StringField::InitField(void)
|
||||
{
|
||||
Type = FIELD_STRING;
|
||||
String=0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
StringField::StringField()
|
||||
{
|
||||
InitField();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
StringField::~StringField()
|
||||
{
|
||||
if (String)
|
||||
CFRelease(String);
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void StringField::ReadTypedData(const uint8_t *data, size_t len)
|
||||
{
|
||||
unsigned short c;
|
||||
|
||||
CHECK_SHORT(len);
|
||||
c = (unsigned short)(data[0]|(data[1]<<8));
|
||||
data+=2;
|
||||
if (c)
|
||||
{
|
||||
bool unicode=false;
|
||||
if (c >= 2 // enough room for BOM
|
||||
&& (c % 2) == 0) // can't be unicode if it's not an even multiple of 2
|
||||
{
|
||||
wchar_t BOM=0;
|
||||
memcpy(&BOM, data, 2);
|
||||
if (BOM == 0xFEFF || BOM == 0xFFFE)
|
||||
{
|
||||
unicode=true;
|
||||
}
|
||||
}
|
||||
|
||||
CHECK_BIN(len, c);
|
||||
if (unicode)
|
||||
{
|
||||
if (String)
|
||||
CFRelease(String);
|
||||
String = CFStringCreateWithBytes(kCFAllocatorDefault, data, c, kCFStringEncodingUTF16, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (String)
|
||||
CFRelease(String);
|
||||
String = CFStringCreateWithBytes(kCFAllocatorDefault, data, c, kCFStringEncodingWindowsLatin1, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void StringField::WriteTypedData(uint8_t *data, size_t len)
|
||||
{
|
||||
int pos=0;
|
||||
|
||||
CHECK_SHORT(len);
|
||||
if (String)
|
||||
{
|
||||
CFIndex lengthRequired=0;
|
||||
CFStringGetBytes(String, CFRangeMake(0, CFStringGetLength(String)), kCFStringEncodingUTF16, 0, true, NULL, 0, &lengthRequired);
|
||||
CHECK_BIN(len, lengthRequired+2);
|
||||
PUT_SHORT(lengthRequired); pos+=2;
|
||||
|
||||
CFStringGetBytes(String, CFRangeMake(0, CFStringGetLength(String)), kCFStringEncodingUTF16, 0, true, data+pos, lengthRequired, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
PUT_SHORT(0);
|
||||
}
|
||||
}
|
||||
|
||||
CFStringRef StringField::GetString()
|
||||
{
|
||||
return String;
|
||||
}
|
||||
|
||||
void StringField::SetNDEString(CFStringRef Str)
|
||||
{
|
||||
if (!Str)
|
||||
return;
|
||||
|
||||
CFStringRef old = String;
|
||||
String = (CFStringRef)CFRetain(Str);
|
||||
CFRelease(old);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
size_t StringField::GetDataSize(void)
|
||||
{
|
||||
if (String)
|
||||
{
|
||||
CFIndex lengthRequired=0;
|
||||
CFStringGetBytes(String, CFRangeMake(0, CFStringGetLength(String)), kCFStringEncodingUTF16, 0, true, NULL, 0, &lengthRequired);
|
||||
return lengthRequired+2;
|
||||
}
|
||||
else
|
||||
return 2;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int StringField::Compare(Field *Entry)
|
||||
{
|
||||
if (!Entry) return -1;
|
||||
if (Entry->GetType() != GetType()) return 0;
|
||||
|
||||
CFStringRef compareString = ((StringField*)Entry)->GetString();
|
||||
if (!String && !compareString) return 0;
|
||||
if (!String && compareString) return 1;
|
||||
if (!compareString) return -1;
|
||||
|
||||
return CFStringCompare(String, compareString, kCFCompareCaseInsensitive|kCFCompareNonliteral|kCFCompareDiacriticInsensitive);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int StringField::Starts(Field *Entry)
|
||||
{
|
||||
if (!Entry) return -1;
|
||||
if (Entry->GetType() != GetType()) return 0;
|
||||
|
||||
CFStringRef compareString = ((StringField*)Entry)->GetString();
|
||||
if (!String || !compareString) return 0;
|
||||
|
||||
CFRange findRange = CFStringFind(String, compareString, kCFCompareCaseInsensitive|kCFCompareNonliteral|kCFCompareAnchored|kCFCompareDiacriticInsensitive);
|
||||
if (findRange.location == kCFNotFound)
|
||||
return 0;
|
||||
return findRange.location == 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
int StringField::Contains(Field *Entry)
|
||||
{
|
||||
if (!Entry) return -1;
|
||||
if (Entry->GetType() != GetType()) return 0;
|
||||
|
||||
CFStringRef compareString = ((StringField*)Entry)->GetString();
|
||||
if (!String || !compareString) return 0;
|
||||
|
||||
CFRange findRange = CFStringFind(String, compareString, kCFCompareCaseInsensitive|kCFCompareNonliteral|kCFCompareDiacriticInsensitive);
|
||||
return findRange.location != kCFNotFound;
|
||||
|
||||
}
|
||||
|
||||
Field *StringField::Clone(Table *pTable)
|
||||
{
|
||||
StringField *clone = new StringField(String);
|
||||
clone->Pos = FIELD_CLONE;
|
||||
clone->ID = ID;
|
||||
clone->MaxSizeOnDisk = GetDataSize();
|
||||
return clone;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
bool StringField::ApplyFilter(Field *Data, int op)
|
||||
{
|
||||
if (op == FILTER_ISEMPTY || op == FILTER_ISNOTEMPTY)
|
||||
{
|
||||
bool r = (op == FILTER_ISEMPTY);
|
||||
if (!String)
|
||||
return r;
|
||||
|
||||
if (CFStringGetLength(String) == 0)
|
||||
return r;
|
||||
|
||||
return !r;
|
||||
}
|
||||
//
|
||||
bool r;
|
||||
StringField *compField = (StringField *)Data;
|
||||
switch (op)
|
||||
{
|
||||
case FILTER_EQUALS:
|
||||
r = !Compare(Data);
|
||||
break;
|
||||
case FILTER_NOTEQUALS:
|
||||
r = !!Compare(Data);
|
||||
break;
|
||||
case FILTER_CONTAINS:
|
||||
r = !!Contains(Data);
|
||||
break;
|
||||
case FILTER_NOTCONTAINS:
|
||||
r = !Contains(Data);
|
||||
break;
|
||||
case FILTER_ABOVE:
|
||||
r = (bool)(Compare(Data) > 0);
|
||||
break;
|
||||
case FILTER_ABOVEOREQUAL:
|
||||
r = (bool)(Compare(compField) >= 0);
|
||||
break;
|
||||
case FILTER_BELOW:
|
||||
r = (bool)(Compare(compField) < 0);
|
||||
break;
|
||||
case FILTER_BELOWOREQUAL:
|
||||
r = (bool)(Compare(compField) <= 0);
|
||||
break;
|
||||
case FILTER_BEGINS:
|
||||
r = !!Starts(compField);
|
||||
break;
|
||||
case FILTER_ENDS:
|
||||
{
|
||||
CFStringRef compareString = ((StringField*)Data)->GetString();
|
||||
if (!String || !compareString) return 0;
|
||||
|
||||
CFRange findRange = CFStringFind(String, compareString, kCFCompareCaseInsensitive|kCFCompareNonliteral|kCFCompareAnchored|kCFCompareBackwards);
|
||||
if (findRange.location == kCFNotFound)
|
||||
r=0;
|
||||
else
|
||||
r = findRange.location != 0;
|
||||
}
|
||||
break;
|
||||
case FILTER_LIKE:
|
||||
/* TODO
|
||||
if (compField->optimized_the)
|
||||
p = compField->optimized_the;
|
||||
else
|
||||
{
|
||||
SKIP_THE_AND_WHITESPACEW(p);
|
||||
compField->optimized_the = p;
|
||||
}
|
||||
|
||||
if (optimized_the)
|
||||
d = optimized_the;
|
||||
else
|
||||
{
|
||||
SKIP_THE_AND_WHITESPACEW(d);
|
||||
optimized_the=d;
|
||||
}
|
||||
r = (bool)(nde_wcsicmp(d, p) == 0);
|
||||
*/
|
||||
r = !!Compare(compField);
|
||||
break;
|
||||
case FILTER_BEGINSLIKE:
|
||||
/*
|
||||
if (compField->optimized_the)
|
||||
p = compField->optimized_the;
|
||||
else
|
||||
{
|
||||
SKIP_THE_AND_WHITESPACEW(p);
|
||||
compField->optimized_the = p;
|
||||
}
|
||||
|
||||
if (optimized_the)
|
||||
d = optimized_the;
|
||||
else
|
||||
{
|
||||
SKIP_THE_AND_WHITESPACEW(d);
|
||||
optimized_the=d;
|
||||
}
|
||||
|
||||
r = (bool)(nde_wcsnicmp(d, p, wcslen(p)) == 0);
|
||||
*/
|
||||
r = !!Starts(compField);
|
||||
break;
|
||||
default:
|
||||
r = true;
|
||||
break;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
50
Src/nde/osx/StringField.h
Normal file
50
Src/nde/osx/StringField.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
/*
|
||||
---------------------------------------------------------------------------
|
||||
|
||||
StringField Class Prototypes
|
||||
|
||||
---------------------------------------------------------------------------
|
||||
*/
|
||||
|
||||
#ifndef __STRINGFIELD_H
|
||||
#define __STRINGFIELD_H
|
||||
|
||||
#include <CoreFoundation/CFString.h>
|
||||
|
||||
class StringField : public Field
|
||||
{
|
||||
|
||||
public:
|
||||
StringField();
|
||||
~StringField();
|
||||
|
||||
StringField(CFStringRef Str);
|
||||
CFStringRef GetString(); // CFRetain this if you need to keep it for a while
|
||||
void SetNDEString(CFStringRef str);
|
||||
|
||||
protected:
|
||||
virtual void ReadTypedData(const uint8_t *, size_t len);
|
||||
virtual void WriteTypedData(uint8_t *, size_t len);
|
||||
virtual size_t GetDataSize(void);
|
||||
virtual int Compare(Field *Entry);
|
||||
virtual int Starts(Field *Entry);
|
||||
virtual int Contains(Field *Entry);
|
||||
|
||||
virtual bool ApplyFilter(Field *Data, int op);
|
||||
virtual Field *Clone(Table *pTable);
|
||||
void InitField(void);
|
||||
|
||||
CFStringRef String;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
659
Src/nde/osx/Table.cpp
Normal file
659
Src/nde/osx/Table.cpp
Normal file
|
@ -0,0 +1,659 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Table Class
|
||||
Apple Mac OS X implementation
|
||||
--------------------------------------------------------------------------- */
|
||||
#include "../nde.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "../CRC.H"
|
||||
|
||||
const char *tSign="NDETABLE";
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Table::Table(const char *TableName, const char *Idx, BOOL Create, Database *_db, BOOL _Cached)
|
||||
: columns_cached(false), use_row_cache(false), Scanner(this)
|
||||
{
|
||||
Handle = 0;
|
||||
memset(column_ids, FIELD_UNKNOWN, 255);
|
||||
Cached = _Cached;
|
||||
db = _db;
|
||||
AutoCreate = Create;
|
||||
Name = strdup(TableName);
|
||||
IdxName = strdup(Idx);
|
||||
Init();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::Init()
|
||||
{
|
||||
numErrors = 0;
|
||||
Scanners = new LinkedList();
|
||||
// benski> cut: Handle=NULL;
|
||||
IdxHandle=NULL;
|
||||
FieldsRecord=NULL;
|
||||
IndexList=NULL;
|
||||
GLocateUpToDate = FALSE;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Table::~Table()
|
||||
{
|
||||
Reset();
|
||||
if (Handle) // Reset doesn't completely destroy Handle
|
||||
Vfdestroy(Handle);
|
||||
Handle = 0;
|
||||
|
||||
free(Name);
|
||||
free(IdxName);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::Reset()
|
||||
{
|
||||
if (IndexList) IndexList->Release();
|
||||
IndexList=0;
|
||||
if (FieldsRecord) FieldsRecord->Release();
|
||||
FieldsRecord=0;
|
||||
delete Scanners;
|
||||
Scanners=0;
|
||||
if (Handle)
|
||||
Vfclose(Handle); // close (but don't destroy) to keep mutex open.
|
||||
if (IdxHandle)
|
||||
Vfdestroy(IdxHandle);
|
||||
IdxHandle = 0;
|
||||
|
||||
for (RowCache::iterator itr=rowCache.begin();itr!=rowCache.end();itr++)
|
||||
{
|
||||
if (itr->second)
|
||||
itr->second->Release();
|
||||
}
|
||||
rowCache.clear();
|
||||
|
||||
memset(column_ids, FIELD_UNKNOWN, 255);
|
||||
columns_cached=false;
|
||||
}
|
||||
|
||||
|
||||
struct IndexNewWalkerContext
|
||||
{
|
||||
IndexNewWalkerContext(Table *_table)
|
||||
{
|
||||
N = -1;
|
||||
table = _table;
|
||||
}
|
||||
int N;
|
||||
Table *table;
|
||||
};
|
||||
|
||||
bool Table::IndexNewWalker(IndexRecord *record, Field *entry, void *context_in)
|
||||
{
|
||||
IndexNewWalkerContext *context = (IndexNewWalkerContext *)context_in;
|
||||
IndexField *p = (IndexField *)entry;
|
||||
p->index = new Index(context->table->IdxHandle, p->ID, context->N++, p->Type, FALSE, 0, context->table);
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL Table::Open(void)
|
||||
{
|
||||
BOOL Valid;
|
||||
int justcreated = 0;
|
||||
|
||||
if (!Handle)
|
||||
Handle = Vfnew(Name, "r+b", Cached);
|
||||
if (!Handle) return FALSE;
|
||||
if (!Vflock(Handle))
|
||||
{
|
||||
Vfdestroy(Handle);
|
||||
Handle = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
Handle = Vfopen(Handle, Name, "r+b", Cached);
|
||||
IdxHandle = Vfopen(0, IdxName, "r+b", TRUE);
|
||||
Valid = (Handle && IdxHandle);
|
||||
|
||||
// unlock
|
||||
if (Valid || !AutoCreate)
|
||||
{
|
||||
//if (Handle)
|
||||
//Vfunlock(Handle);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Handle)
|
||||
{
|
||||
Vfclose(Handle);
|
||||
if (IdxHandle)
|
||||
Vfdestroy(IdxHandle);
|
||||
IdxHandle = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (IdxHandle)
|
||||
Vfdestroy(IdxHandle);
|
||||
IdxHandle = 0;
|
||||
Handle = Vfnew(Name, "w+b", Cached);
|
||||
if (!Vflock(Handle))
|
||||
{
|
||||
Vfdestroy(Handle);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
Handle = Vfopen(Handle, Name, "w+b", Cached);
|
||||
IdxHandle = Vfopen(0, IdxName, "w+b", TRUE);
|
||||
Valid = (Handle && IdxHandle);
|
||||
|
||||
if (Valid)
|
||||
{
|
||||
Vfwrite(__TABLE_SIGNATURE__, strlen(__TABLE_SIGNATURE__), Handle);
|
||||
Vfwrite(__INDEX_SIGNATURE__, strlen(__TABLE_SIGNATURE__), IdxHandle);
|
||||
// TODO bensk> change if NUM_SPECIAL_RECORDS ever increases
|
||||
int v=NUM_SPECIAL_RECORDS;//strlen(__TABLE_SIGNATURE__);
|
||||
Vfwrite(&v, sizeof(v), IdxHandle);
|
||||
// v = 0; fwrite(&v, sizeof(v), 1, IdxHandle);
|
||||
v = -1; Vfwrite(&v, sizeof(v), IdxHandle); // write ID
|
||||
v = 0;
|
||||
for (int i=0;i<NUM_SPECIAL_RECORDS;i++)
|
||||
{
|
||||
Vfwrite(&v, sizeof(v), IdxHandle);
|
||||
Vfwrite(&v, sizeof(v), IdxHandle);
|
||||
}
|
||||
Sync();
|
||||
justcreated = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!Valid)
|
||||
{
|
||||
if (Handle) Vfdestroy(Handle);
|
||||
if (IdxHandle) Vfdestroy(IdxHandle);
|
||||
Handle = NULL;
|
||||
IdxHandle = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
int Ptr;
|
||||
|
||||
char test1[9]={0,};
|
||||
char test2[9]={0,};
|
||||
|
||||
Vfseek(Handle, 0, SEEK_SET);
|
||||
Vfread(test1, strlen(__TABLE_SIGNATURE__), Handle);
|
||||
Vfseek(IdxHandle, 0, SEEK_SET);
|
||||
Vfread(test2, strlen(__INDEX_SIGNATURE__), IdxHandle);
|
||||
test1[8]=0;
|
||||
test2[8]=0;
|
||||
if (strcmp(test1, __TABLE_SIGNATURE__) || strcmp(test2, __INDEX_SIGNATURE__))
|
||||
{
|
||||
if (Handle) Vfdestroy(Handle);
|
||||
Handle = 0;
|
||||
if (IdxHandle) Vfdestroy(IdxHandle);
|
||||
IdxHandle = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Load default index
|
||||
IndexField *field;
|
||||
|
||||
field = new IndexField(PRIMARY_INDEX, -1, -1, CFSTR("None"));
|
||||
field->index = new Index(IdxHandle, PRIMARY_INDEX, -1, -1, FALSE, 0, this);
|
||||
|
||||
// Get indexes
|
||||
Ptr = field->index->Get(INDEX_RECORD_NUM);
|
||||
IndexList = new IndexRecord(Ptr, INDEX_RECORD_NUM, Handle, this);
|
||||
if (!IndexList)
|
||||
{
|
||||
delete field;
|
||||
if (Handle) Vfdestroy(Handle);
|
||||
Handle = 0;
|
||||
if (IdxHandle) Vfdestroy(IdxHandle);
|
||||
IdxHandle = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Init them
|
||||
IndexNewWalkerContext newContext(this);
|
||||
IndexList->WalkFields(IndexNewWalker, &newContext);
|
||||
|
||||
// Add default in case its not there (if it is it won't be added by addfield)
|
||||
IndexList->AddField(field);
|
||||
|
||||
// Get the default index (whether loaded or preloaded)
|
||||
Scanner::index = ((IndexField*)IndexList->GetField(PRIMARY_INDEX))->index;
|
||||
|
||||
// If it's different from preloaded, delete preloaded
|
||||
if (field->index != Scanner::index)
|
||||
{
|
||||
delete field;
|
||||
field=0;
|
||||
}
|
||||
|
||||
// Set up colaboration
|
||||
IndexList->BuildCollaboration();
|
||||
|
||||
// Get columns
|
||||
Ptr = Scanner::index->Get(FIELDS_RECORD_NUM);
|
||||
FieldsRecord = new Record(Ptr, FIELDS_RECORD_NUM, Handle, this);
|
||||
if (!FieldsRecord)
|
||||
{
|
||||
IndexList->Release();
|
||||
IndexList=0;
|
||||
if (Handle) Vfdestroy(Handle);
|
||||
Handle = 0;
|
||||
if (IdxHandle) Vfdestroy(IdxHandle);
|
||||
IdxHandle = 0;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// update the column cache
|
||||
FieldsRecord->WalkFields(BuildColumnCache, this);
|
||||
columns_cached=true;
|
||||
}
|
||||
|
||||
#if 0 // TODO
|
||||
if (Valid && !justcreated)
|
||||
{
|
||||
if (IndexList->NeedFix())
|
||||
Compact();
|
||||
}
|
||||
#endif
|
||||
if (Valid) First();
|
||||
if (Handle)
|
||||
Vfunlock(Handle);
|
||||
return Valid;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::Close(void)
|
||||
{
|
||||
int v=0;
|
||||
|
||||
if (Handle && IndexList && Vflock(Handle, 0))
|
||||
{
|
||||
IndexList->WalkFields(IndexWriteWalker, 0);
|
||||
}
|
||||
|
||||
delete Scanners;
|
||||
Scanners = NULL;
|
||||
|
||||
Vsync(Handle);
|
||||
if (IdxHandle)
|
||||
{
|
||||
Vfdestroy(IdxHandle);
|
||||
IdxHandle = NULL;
|
||||
v |= 2;
|
||||
}
|
||||
if (Handle)
|
||||
{
|
||||
Vfdestroy(Handle);
|
||||
Handle = NULL;
|
||||
v |= 1;
|
||||
}
|
||||
|
||||
if (v != 3)
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
bool Table::IndexWriteWalker(IndexRecord *record, Field *entry, void *context)
|
||||
{
|
||||
IndexField *field = (IndexField *)entry;
|
||||
field->index->WriteIndex();
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::Sync(void)
|
||||
{
|
||||
if (!Vflock(Handle))
|
||||
return;
|
||||
|
||||
if (IndexList)
|
||||
IndexList->WalkFields(IndexWriteWalker, 0);
|
||||
|
||||
int err=0;
|
||||
if (!err && Handle) err|=Vsync(Handle);
|
||||
if (!err && IdxHandle) err|=Vsync(IdxHandle);
|
||||
|
||||
Vfunlock(Handle);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
ColumnField *Table::NewColumn(unsigned char FieldID, CFStringRef FieldName, unsigned char FieldType, BOOL indexUnique)
|
||||
{
|
||||
columns_cached=false; // if they start writing new columns, kill the columns cache until they PostColumns()
|
||||
ColumnField *f = GetColumnById(FieldID);
|
||||
if (f) {
|
||||
int t = f->GetDataType();
|
||||
if (t != FieldType) {
|
||||
if (CompatibleFields(t, FieldType))
|
||||
{
|
||||
f->SetDataType(FieldType);
|
||||
goto aok;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
aok:
|
||||
if (GetColumnByName(FieldName))
|
||||
return NULL;
|
||||
ColumnField *field = new ColumnField(FieldID, FieldName, FieldType, this);
|
||||
column_ids[FieldID]=FieldType;
|
||||
FieldsRecord->AddField(field);
|
||||
return field;
|
||||
}
|
||||
|
||||
void Table::SetFieldSearchableById(unsigned char field_id, bool searchable)
|
||||
{
|
||||
ColumnField *column = GetColumnById(field_id);
|
||||
if (column)
|
||||
column->SetSearchable(searchable);
|
||||
if (searchable)
|
||||
{
|
||||
search_fields.insert(field_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
search_fields.erase(field_id);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
bool Table::BuildColumnCache(Record *record, Field *entry, void *context)
|
||||
{
|
||||
Table *table = (Table *)context;
|
||||
ColumnField *column = (ColumnField *)entry;
|
||||
unsigned char field_id=column->GetFieldId();
|
||||
table->column_ids[field_id] = column->GetDataType();
|
||||
|
||||
if (column->IsSearchableField())
|
||||
{
|
||||
table->search_fields.insert(field_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
table->search_fields.erase(field_id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::PostColumns(void)
|
||||
{
|
||||
FieldsRecord->WriteFields(this, FIELDS_RECORD_NUM);
|
||||
memset(column_ids, FIELD_UNKNOWN, 255);
|
||||
FieldsRecord->WalkFields(BuildColumnCache, this);
|
||||
columns_cached=true;
|
||||
}
|
||||
|
||||
unsigned char Table::GetColumnType(unsigned char Id)
|
||||
{
|
||||
if (columns_cached)
|
||||
{
|
||||
return column_ids[Id];
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetColumnById(Id)->GetDataType();
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
IndexField *Table::GetIndexByName(CFStringRef name)
|
||||
{
|
||||
if (!IndexList)
|
||||
return NULL;
|
||||
return IndexList->GetIndexByName(name);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
IndexField *Table::GetIndexById(unsigned char Id)
|
||||
{
|
||||
if (!IndexList)
|
||||
return NULL;
|
||||
return (IndexField *)IndexList->GetField(Id);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::AddIndexByName(CFStringRef name, CFStringRef desc)
|
||||
{
|
||||
ColumnField *header = GetColumnByName(name);
|
||||
if (header)
|
||||
{
|
||||
unsigned char Idx = header->ID;
|
||||
AddIndexById(Idx, desc);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::AddIndexById(unsigned char Id, CFStringRef desc)
|
||||
{
|
||||
if (GetIndexById(Id)) return;
|
||||
ColumnField *col = GetColumnById(Id);
|
||||
if (!col)
|
||||
return;
|
||||
IndexField *newindex = new IndexField(Id, IndexList->GetColumnCount(), col->GetDataType(), desc);
|
||||
newindex->index = new Index(IdxHandle, Id, IndexList->GetColumnCount(), col->GetDataType(), TRUE, Scanner::index->NEntries, this);
|
||||
IndexList->AddField(newindex);
|
||||
|
||||
IndexField *previous = (IndexField *)newindex->prev;
|
||||
previous->index->Colaborate(newindex);
|
||||
IndexField *primary_index = (IndexField *)IndexList->GetField(PRIMARY_INDEX);
|
||||
newindex->index->Colaborate(primary_index);
|
||||
|
||||
previous->index->Propagate();
|
||||
|
||||
IndexList->WriteFields(this);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL Table::CheckIndexing(void)
|
||||
{
|
||||
if (IndexList->GetColumnCount() == 0) return TRUE;
|
||||
|
||||
for (int i=0;i<Scanner::index->NEntries;i++)
|
||||
{
|
||||
if (!IndexList->CheckIndexing(i))
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
struct IndexWalkerThunkContext
|
||||
{
|
||||
void *context;
|
||||
Table *_this;
|
||||
Table::IndexWalker callback;
|
||||
};
|
||||
|
||||
bool Table::IndexWalkerThunk(IndexRecord *record, Field *entry, void *context_in)
|
||||
{
|
||||
IndexWalkerThunkContext *context = (IndexWalkerThunkContext *)context_in;
|
||||
return context->callback(context->_this, (IndexField *)entry, context->context);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::WalkIndices(IndexWalker callback, void *context)
|
||||
{
|
||||
if (IndexList && callback)
|
||||
{
|
||||
IndexWalkerThunkContext walkerContext = { context, this, callback };
|
||||
IndexList->WalkFields(IndexWalkerThunk, &walkerContext);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::DropIndex(IndexField *Ptr)
|
||||
{
|
||||
if (!Ptr || Ptr->Type != FIELD_INDEX) return;
|
||||
if (Scanner::index == Ptr->index)
|
||||
{
|
||||
Scanner::index = ((IndexField*)IndexList->GetField(PRIMARY_INDEX))->index;
|
||||
|
||||
IndexList->BuildCollaboration();
|
||||
}
|
||||
IndexList->RemoveField(Ptr);
|
||||
if (Scanner::index->SecIndex == Ptr)
|
||||
Scanner::index->SecIndex = 0;
|
||||
IndexList->SetModified(TRUE);
|
||||
IndexList->WriteFields(this);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::DropIndexByName(CFStringRef desc)
|
||||
{
|
||||
IndexField *indx = GetIndexByName(desc);
|
||||
if (CFStringCompare(desc, CFSTR("None"), kCFCompareCaseInsensitive) == kCFCompareEqualTo)
|
||||
return;
|
||||
|
||||
if (indx)
|
||||
DropIndex(indx);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::DropIndexById(unsigned char Id)
|
||||
{
|
||||
if (!IndexList)
|
||||
return;
|
||||
if (Id == (unsigned char)PRIMARY_INDEX) return;
|
||||
IndexField *indx=(IndexField *)IndexList->GetField(Id);
|
||||
if (indx)
|
||||
DropIndex(indx);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
BOOL Table::LocateByIdEx(int Id, int From, Field *field, int comp_mode)
|
||||
{
|
||||
return Scanner::LocateByIdEx(Id, From, field, NULL, comp_mode);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Record *Table::GetColumns(void)
|
||||
{
|
||||
if (!FieldsRecord)
|
||||
return NULL;
|
||||
return FieldsRecord;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Scanner *Table::NewScanner()
|
||||
{
|
||||
Scanner *s = new Scanner(this);
|
||||
/*if (Scanners->GetNElements() > 0)*/
|
||||
s->index = Scanner::index;
|
||||
Scanners->AddEntry(s, TRUE);
|
||||
return s;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
Scanner *Table::GetDefaultScanner(void)
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::DeleteScanner(Scanner *scan)
|
||||
{
|
||||
if (!scan) return;
|
||||
Scanners->RemoveEntry(scan);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::IndexModified(void)
|
||||
{
|
||||
Scanner *s = (Scanner *)Scanners->GetHead();
|
||||
while (s)
|
||||
{
|
||||
s->IndexModified();
|
||||
s = (Scanner *)s->GetNext();
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
void Table::SetGlobalLocateUpToDate(BOOL is) {
|
||||
GLocateUpToDate = is;
|
||||
}
|
||||
|
||||
ColumnField *Table::GetColumnById(unsigned char Idx)
|
||||
{
|
||||
if (!FieldsRecord)
|
||||
return NULL;
|
||||
return (ColumnField *)FieldsRecord->GetField(Idx);
|
||||
}
|
||||
|
||||
ColumnField *Table::GetColumnByName(CFStringRef FieldName)
|
||||
{
|
||||
return FieldsRecord->GetColumnByName(FieldName);
|
||||
}
|
||||
|
||||
void Table::RowCache_Delete(int position)
|
||||
{
|
||||
if (use_row_cache)
|
||||
{
|
||||
RowCache::iterator found = rowCache.find(position);
|
||||
if (found != rowCache.end())
|
||||
{
|
||||
if (found->second)
|
||||
found->second->Release();
|
||||
rowCache.erase(found);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Table::RowCache_Remove(int position)
|
||||
{
|
||||
if (use_row_cache)
|
||||
{
|
||||
|
||||
Record *&row = rowCache[position];
|
||||
if (row)
|
||||
{
|
||||
row->Release();
|
||||
}
|
||||
|
||||
row = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Table::RowCache_Add(Record *record, int position)
|
||||
{
|
||||
if (use_row_cache)
|
||||
{
|
||||
record->Retain();
|
||||
|
||||
Record *&row = rowCache[position];
|
||||
if (row)
|
||||
{
|
||||
row->Release();
|
||||
}
|
||||
|
||||
row = record;
|
||||
}
|
||||
}
|
||||
|
||||
Record *Table::RowCache_Get(int position)
|
||||
{
|
||||
if (!use_row_cache)
|
||||
return 0;
|
||||
Record *row = rowCache[position];
|
||||
if (row)
|
||||
row->Retain();
|
||||
return row;
|
||||
}
|
||||
|
||||
void Table::EnableRowCache()
|
||||
{
|
||||
use_row_cache=true;
|
||||
}
|
165
Src/nde/osx/Table.h
Normal file
165
Src/nde/osx/Table.h
Normal file
|
@ -0,0 +1,165 @@
|
|||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Table Class Prototypes
|
||||
Apple Mac OS X implementation
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef __TABLE_H
|
||||
#define __TABLE_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include "Scanner.h"
|
||||
#include <map>
|
||||
#include "IndexRecord.h"
|
||||
class Table : private Scanner
|
||||
{
|
||||
public:
|
||||
// TODO: move these back to protected
|
||||
VFILE *Handle;
|
||||
using Scanner::index;
|
||||
bool use_row_cache;
|
||||
BOOL GLocateUpToDate;
|
||||
private:
|
||||
void Init();
|
||||
void Reset();
|
||||
|
||||
private:
|
||||
LinkedList *Scanners;
|
||||
|
||||
protected:
|
||||
char *Name; // TODO: CFStringRef
|
||||
char *IdxName; // TODO: CFStringRef
|
||||
|
||||
VFILE *IdxHandle;
|
||||
BOOL AutoCreate;
|
||||
Record *FieldsRecord;
|
||||
IndexRecord *IndexList;
|
||||
Database *db;
|
||||
BOOL Cached;
|
||||
int numErrors;
|
||||
using Scanner::Edition;
|
||||
bool columns_cached;
|
||||
unsigned char column_ids[256];
|
||||
typedef std::map<int, Record*> RowCache;
|
||||
RowCache rowCache;
|
||||
|
||||
// Tables
|
||||
static bool Compact_ColumnWalk(Record *record, Field *entry, void *context_in);
|
||||
static bool Compact_ColumnWalk2(Record *record, Field *entry, void *context_in);
|
||||
static bool Compact_IndexWalk(Table *table, IndexField *entry, void *context);
|
||||
static bool IndexWriteWalker(IndexRecord *record, Field *entry, void *context);
|
||||
static bool IndexWalkerThunk(IndexRecord *record, Field *entry, void *context);
|
||||
static bool IndexNewWalker(IndexRecord *record, Field *entry, void *context);
|
||||
static bool BuildColumnCache(Record *record, Field *entry, void *context);
|
||||
public:
|
||||
typedef bool (*IndexWalker)(Table *table, IndexField *entry, void *context);
|
||||
Table(const char *TableName, const char *IdxName, BOOL Create, Database *db, BOOL Cached);
|
||||
~Table();
|
||||
BOOL Open(void);
|
||||
void Close(void);
|
||||
|
||||
// Columns
|
||||
ColumnField *NewColumn(unsigned char Id, CFStringRef name, unsigned char type, BOOL indexUniques);
|
||||
|
||||
void DeleteColumn(ColumnField *field); // todo
|
||||
void DeleteColumnByName(const wchar_t *name); // todo
|
||||
void DeleteColumnById(unsigned char Id); // todo
|
||||
void PostColumns(void);
|
||||
NDE_API Record *GetColumns(void);
|
||||
ColumnField *GetColumnByName(CFStringRef FieldName);
|
||||
ColumnField *GetColumnById(unsigned char Idx);
|
||||
unsigned char GetColumnType(unsigned char Id);
|
||||
|
||||
// Fields
|
||||
using Scanner::NewFieldByName;
|
||||
using Scanner::NewFieldById;
|
||||
using Scanner::GetFieldByName;
|
||||
using Scanner::GetFieldById;
|
||||
using Scanner::DeleteField;
|
||||
using Scanner::DeleteFieldByName;
|
||||
using Scanner::DeleteFieldById;
|
||||
|
||||
// Records
|
||||
using Scanner::First;
|
||||
using Scanner::Last;
|
||||
using Scanner::Next;
|
||||
using Scanner::Previous;
|
||||
using Scanner::Eof;
|
||||
using Scanner::Bof;
|
||||
using Scanner::New;
|
||||
using Scanner::Insert;
|
||||
using Scanner::Edit;
|
||||
using Scanner::Cancel;
|
||||
using Scanner::Post;
|
||||
using Scanner::Delete;
|
||||
using Scanner::GetRecordsCount;
|
||||
using Scanner::GetRecordById;
|
||||
using Scanner::GetRecordId;
|
||||
void Sync(void);
|
||||
using Scanner::LocateByName;
|
||||
using Scanner::LocateById;
|
||||
BOOL LocateByIdEx(int Id, int From, Field *field, int comp_mode);
|
||||
|
||||
// Indexes
|
||||
void AddIndexByName(CFStringRef FieldName, CFStringRef KeyName);
|
||||
void AddIndexById(unsigned char Id, CFStringRef KeyName);
|
||||
|
||||
void WalkIndices(IndexWalker callback, void *context);
|
||||
|
||||
IndexField *GetIndexByName(CFStringRef name);
|
||||
IndexField *GetIndexById(unsigned char Id);
|
||||
using Scanner::SetWorkingIndexByName;
|
||||
using Scanner::SetWorkingIndexById;
|
||||
NDE_API BOOL CheckIndexing(void);
|
||||
void DropIndexByName(CFStringRef desc);
|
||||
void DropIndexById(unsigned char Id);
|
||||
void DropIndex(IndexField *Ptr);
|
||||
void IndexModified(void);
|
||||
|
||||
// Filters
|
||||
using Scanner::AddFilterByName;
|
||||
using Scanner::AddFilterById;
|
||||
using Scanner::AddFilterOp;
|
||||
using Scanner::RemoveFilters;
|
||||
|
||||
// Scanners
|
||||
Scanner *NewScanner();
|
||||
Scanner *GetDefaultScanner(void);
|
||||
void DeleteScanner(Scanner *scan);
|
||||
|
||||
// Misc
|
||||
using Scanner::FragmentationLevel;
|
||||
void Compact(int *progress = NULL);
|
||||
void SetGlobalLocateUpToDate(BOOL is);
|
||||
|
||||
// Row Cache
|
||||
void RowCache_Delete(int position);
|
||||
void RowCache_Remove(int position);
|
||||
void RowCache_Add(Record *record, int position);
|
||||
Record *RowCache_Get(int position);
|
||||
NDE_API void EnableRowCache();
|
||||
|
||||
// Searching
|
||||
void SetFieldSearchableById(unsigned char field_id, bool searchable);
|
||||
|
||||
int HasErrors()
|
||||
{
|
||||
return numErrors > 0;
|
||||
}
|
||||
int NumErrors()
|
||||
{
|
||||
return numErrors;
|
||||
}
|
||||
void IncErrorCount()
|
||||
{
|
||||
numErrors++;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
542
Src/nde/osx/Vfs.cpp
Normal file
542
Src/nde/osx/Vfs.cpp
Normal file
|
@ -0,0 +1,542 @@
|
|||
|
||||
/* ---------------------------------------------------------------------------
|
||||
Nullsoft Database Engine
|
||||
--------------------
|
||||
codename: Near Death Experience
|
||||
--------------------------------------------------------------------------- */
|
||||
|
||||
/* ---------------------------------------------------------------------------
|
||||
|
||||
Virtual File System
|
||||
|
||||
--------------------------------------------------------------------------- */
|
||||
#include "nde.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include "Vfs.h"
|
||||
|
||||
#ifndef EOF
|
||||
#define EOF -1
|
||||
#endif
|
||||
#include "../nu/strsafe.h"
|
||||
/* the FILE (fopen/fwrite/etc) implementation for Mac and Linux */
|
||||
|
||||
|
||||
|
||||
VFILE *Vfnew(const char *fl, const char *mode, BOOL Cached)
|
||||
{
|
||||
if (!fl) return NULL;
|
||||
VFILE *f = (VFILE *)malloc(sizeof(VFILE));
|
||||
if (!f)
|
||||
return NULL;
|
||||
memset(f, 0, sizeof(VFILE));
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
f->cached = Cached;
|
||||
#else
|
||||
f->cached = TRUE;
|
||||
#endif
|
||||
|
||||
if (!strchr(mode, '+'))
|
||||
{
|
||||
if (strchr(mode, 'r'))
|
||||
f->mode = VFS_READ | VFS_MUSTEXIST;
|
||||
if (strchr(mode, 'w'))
|
||||
f->mode = VFS_WRITE | VFS_CREATE | VFS_NEWCONTENT;
|
||||
if (strchr(mode, 'a'))
|
||||
f->mode = VFS_WRITE | VFS_CREATE | VFS_SEEKEOF;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strstr(mode, "r+"))
|
||||
f->mode = VFS_WRITE | VFS_MUSTEXIST;
|
||||
if (strstr(mode, "w+"))
|
||||
f->mode = VFS_WRITE | VFS_CREATE | VFS_NEWCONTENT;
|
||||
if (strstr(mode, "a+"))
|
||||
f->mode = VFS_WRITE | VFS_CREATE | VFS_SEEKEOF;
|
||||
}
|
||||
|
||||
if (f->mode == 0 || ((f->mode & VFS_READ) && (f->mode & VFS_WRITE)))
|
||||
{
|
||||
free(f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
snprintf(f->lockname, sizeof(f->lockname), "%s.lock", fl);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
VFILE *Vfopen(VFILE *f, const char *fl, const char *mode, BOOL Cached)
|
||||
{
|
||||
if (!f)
|
||||
{
|
||||
f = Vfnew(fl, mode, Cached);
|
||||
if (!f)
|
||||
return 0;
|
||||
}
|
||||
if (!f && !fl) return NULL;
|
||||
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
f->rfile = fopen(fl, mode);
|
||||
if (f->rfile)
|
||||
|
||||
f->filename = _strdup(fl);
|
||||
}
|
||||
else
|
||||
{
|
||||
free(f);
|
||||
return NULL;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (f->mode & VFS_MUSTEXIST)
|
||||
{
|
||||
if (access(fl, 0) != 0)
|
||||
{
|
||||
free(f);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(f->mode & VFS_NEWCONTENT))
|
||||
{
|
||||
FILE *pf;
|
||||
pf = fopen(fl, "rb");
|
||||
if (!pf)
|
||||
{
|
||||
f->data = (unsigned char *)calloc(VFILE_INC, 1);
|
||||
if (f->data == NULL)
|
||||
{
|
||||
free(f);
|
||||
return NULL;
|
||||
}
|
||||
f->filesize = 0;
|
||||
f->maxsize = VFILE_INC;
|
||||
}
|
||||
else
|
||||
{
|
||||
fseek(pf, 0, SEEK_END);
|
||||
f->filesize = ftell(pf);
|
||||
fseek(pf, 0, SEEK_SET);
|
||||
f->data = (unsigned char *)calloc(f->filesize, 1);
|
||||
if (f->data == NULL)
|
||||
{
|
||||
free(f);
|
||||
return NULL;
|
||||
}
|
||||
f->maxsize = f->filesize;
|
||||
fread(f->data, f->filesize, 1, pf);
|
||||
fclose(pf);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (f->mode & VFS_SEEKEOF)
|
||||
f->ptr = f->filesize;
|
||||
|
||||
f->filename = strdup(fl);
|
||||
return f;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Vfclose(VFILE *f)
|
||||
{
|
||||
if (!f) return;
|
||||
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
free(f->filename);
|
||||
if (f->rfile)
|
||||
fclose(f->rfile);
|
||||
f->rfile=0;
|
||||
// free(f);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!(f->mode & VFS_WRITE))
|
||||
{
|
||||
free(f->filename);
|
||||
free(f->data);
|
||||
//free(f);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Vsync(f);
|
||||
while (f->locks)
|
||||
Vfunlock(f, 1);
|
||||
|
||||
free(f->filename);
|
||||
free(f->data);
|
||||
//free(f);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
size_t Vfread(void *ptr, size_t size, VFILE *f)
|
||||
{
|
||||
if (!ptr || !f) return 0;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
return fread(ptr, 1, size, f->rfile);
|
||||
}
|
||||
#endif
|
||||
size_t s = size;
|
||||
if (!s) return 0;
|
||||
if (s + f->ptr > f->filesize)
|
||||
{
|
||||
//FUCKO: remove this
|
||||
if (!(f->ptr < f->filesize))
|
||||
{
|
||||
// if (!f->flushtable) // this would be ideal, if we could figure out f->flushtable
|
||||
// f->flushtable=MessageBox(g_hwnd,"DB read failed, DB may be corrupted.\r\n\r\n"
|
||||
// "Hit Retry to continue, or Cancel to clear the DB and start over","Winamp Library Error",MB_RETRYCANCEL) == IDCANCEL; //fucko
|
||||
//MessageBox(g_hwnd,"DB read failed, DB may be corrupted. If this error persists, remove all files from the library.",
|
||||
// "Winamp Library Error",MB_OK);
|
||||
return 0;
|
||||
}
|
||||
s = f->filesize - f->ptr;
|
||||
}
|
||||
memcpy(ptr, f->data+f->ptr, s);
|
||||
f->ptr += s;
|
||||
return (s/size);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Vfwrite(const void *ptr, size_t size, VFILE *f)
|
||||
{
|
||||
if (!ptr || !f) return;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
fwrite(ptr, size*n, f->rfile);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
f->dirty=1;
|
||||
if (size + f->ptr > f->maxsize)
|
||||
{
|
||||
// grow f->data,f->maxsize to be (size + f->ptr + VFILE_INC-1)&~(VFILE_INC-1)
|
||||
// instead of calling Vgrow again which gets kinda slow
|
||||
size_t newsize=(size + f->ptr + VFILE_INC-1)&~(VFILE_INC-1);
|
||||
f->data=(unsigned char *)realloc(f->data,newsize);
|
||||
if (f->data == NULL) return;
|
||||
memset(f->data+f->maxsize,0,newsize-f->maxsize);
|
||||
f->maxsize=newsize;
|
||||
}
|
||||
memcpy(f->data + f->ptr, ptr, size);
|
||||
f->ptr += size;
|
||||
if (f->ptr > f->filesize)
|
||||
f->filesize = f->ptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Vgrow(VFILE *f)
|
||||
{
|
||||
if (!f) return;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached) return;
|
||||
#endif
|
||||
f->data = (unsigned char *)realloc(f->data, f->maxsize + VFILE_INC);
|
||||
f->maxsize += VFILE_INC;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Vfputs(char *str, VFILE *f)
|
||||
{
|
||||
if (!f) return;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
fputs(str, f->rfile);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
Vfwrite(str, strlen(str), f);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Vfputc(char c, VFILE *f)
|
||||
{
|
||||
if (!f) return;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
fputc(c, f->rfile);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
Vfwrite(&c, 1, f);
|
||||
}
|
||||
|
||||
/* benski> unused:
|
||||
// not mac compliant
|
||||
//----------------------------------------------------------------------------
|
||||
char *Vfgets(char *dest, int n, VFILE *f) {
|
||||
if (!f) return NULL;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
#ifdef NDE_NOWIN32FILEIO
|
||||
return fgets(dest, n, f->rfile);
|
||||
#else
|
||||
#error port me!
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned char c=0;
|
||||
char *p;
|
||||
int l=0;
|
||||
|
||||
p = dest;
|
||||
while (l < n && !Vfeof(f)) {
|
||||
c = f->data[f->ptr];
|
||||
f->ptr++;
|
||||
*p = c;
|
||||
p++;
|
||||
l++;
|
||||
if (c == '\n') {
|
||||
if (!Vfeof(f) && f->data[f->ptr] == '\r') {
|
||||
f->ptr++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
*p=0;
|
||||
return dest;
|
||||
}
|
||||
*/
|
||||
|
||||
/* benski> unused:
|
||||
//----------------------------------------------------------------------------
|
||||
char Vfgetc(VFILE *f) {
|
||||
if (!f) return EOF;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
#ifdef NDE_NOWIN32FILEIO
|
||||
return fgetc(f->rfile);
|
||||
#else
|
||||
#error port me#
|
||||
#endif
|
||||
#endif
|
||||
if (!Vfeof(f))
|
||||
return f->data[f->ptr++];
|
||||
return EOF;
|
||||
}
|
||||
*/
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
unsigned long Vftell(VFILE *f)
|
||||
{
|
||||
if (!f) return (unsigned)-1;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
return ftell(f->rfile);
|
||||
}
|
||||
#endif
|
||||
return f->ptr;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void Vfseek(VFILE *f, long i, int whence)
|
||||
{
|
||||
if (!f) return;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
fseek(f->rfile, i, whence);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
switch (whence)
|
||||
{
|
||||
case SEEK_SET:
|
||||
f->ptr = i;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
f->ptr += i;
|
||||
break;
|
||||
case SEEK_END:
|
||||
f->ptr = f->filesize+i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int Vfeof(VFILE *f)
|
||||
{
|
||||
if (!f) return -1;
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
return feof(f->rfile);
|
||||
}
|
||||
#endif
|
||||
return (f->ptr >= f->filesize);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
int Vsync(VFILE *f)
|
||||
{
|
||||
if (!f) return 0;
|
||||
if (!f->dirty) return 0;
|
||||
|
||||
if (f->mode & VFS_WRITE)
|
||||
{
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
if (!f->cached)
|
||||
{
|
||||
int p=ftell(f->rfile);
|
||||
fclose(f->rfile);
|
||||
f->rfile = fopen(f->filename, "r+b");
|
||||
if (!f->rfile)
|
||||
return 1;
|
||||
fseek(f->rfile, p, SEEK_SET);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
char newfn[1024], oldfn[1024];
|
||||
DWORD mypid=getpid();
|
||||
|
||||
snprintf(newfn,sizeof(newfn), "%s.n3w%08X",f->filename,mypid);
|
||||
snprintf(oldfn,sizeof(oldfn), "%s.o1d%08X",f->filename,mypid);
|
||||
|
||||
unlink(newfn);
|
||||
unlink(oldfn);
|
||||
|
||||
|
||||
tryagain:
|
||||
FILE *pf = fopen(newfn, "wb");
|
||||
if (!pf || fwrite(f->data, f->filesize, 1, pf) != 1)
|
||||
{
|
||||
if (pf) fclose(pf);
|
||||
|
||||
|
||||
printf("Error flushing DB to disk (is your drive full?)\n\nHit (R)etry to try again (recommended), or (C)ancel to abort (NOT recommended, and may leave the DB in an unuseable state)");
|
||||
fflush(stdout);
|
||||
char c;
|
||||
while (1)
|
||||
{
|
||||
scanf("%c", &c);
|
||||
// clear_stdin();
|
||||
c = toupper(c);
|
||||
if (c == 'R') goto tryagain;
|
||||
else if (c == 'C') break;
|
||||
}
|
||||
unlink(newfn);
|
||||
return 1;
|
||||
}
|
||||
fclose(pf);
|
||||
rename(f->filename,oldfn); // save old file
|
||||
|
||||
|
||||
|
||||
int rv=0;
|
||||
|
||||
tryagain2:
|
||||
if (rename(newfn,f->filename))
|
||||
{
|
||||
|
||||
printf("Error updating DB file on disk. This should never really happen\n\nHit (R)etry to try again (recommended), or (C)ancel to abort (NOT recommended, and may leave the DB in an unuseable state)");
|
||||
fflush(stdout);
|
||||
char c;
|
||||
while (1)
|
||||
{
|
||||
scanf("%c", &c);
|
||||
// clear_stdin();
|
||||
c = toupper(c);
|
||||
if (c == 'R') goto tryagain2;
|
||||
else if (c == 'C') break;
|
||||
}
|
||||
|
||||
rename(oldfn,f->filename); // restore old file
|
||||
rv=1;
|
||||
}
|
||||
|
||||
// clean up our temp files
|
||||
unlink(oldfn);
|
||||
unlink(newfn);
|
||||
|
||||
|
||||
//free(newfn);
|
||||
//free(oldfn);
|
||||
if (rv == 0)
|
||||
f->dirty=0;
|
||||
return rv;
|
||||
}
|
||||
f->dirty=0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Vfdestroy(VFILE *f)
|
||||
{
|
||||
// benski> TODO:
|
||||
if (f)
|
||||
{
|
||||
Vfclose(f);
|
||||
|
||||
while (f->locks)
|
||||
Vfunlock(f, 1);
|
||||
|
||||
// TODO if (f->mutex) CloseHandle(f->mutex);
|
||||
free(f);
|
||||
}
|
||||
}
|
||||
|
||||
// benski> TODO implement these with fopen
|
||||
|
||||
// returns 0 on failure
|
||||
int Vflock(VFILE *fl, BOOL is_sync)
|
||||
{
|
||||
#ifndef NO_TABLE_WIN32_LOCKING
|
||||
if (!fl) return 0;
|
||||
if (!is_sync && fl->cached)
|
||||
return 1;
|
||||
if (fl->locks++ == 0)
|
||||
{
|
||||
int retry_cnt=0;
|
||||
FILE *fFile;
|
||||
do
|
||||
{
|
||||
fFile = fopen(fl->lockname, "wb");
|
||||
if (fFile == 0) Sleep(100);
|
||||
}
|
||||
while (fFile == 0 && retry_cnt++ < 100); // try for 10 seconds
|
||||
|
||||
if (fFile == INVALID_HANDLE_VALUE) return 0; // db already locked, fail gracefully
|
||||
fl->lockFile = fFile;
|
||||
}
|
||||
#endif
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
void Vfunlock(VFILE *fl, BOOL is_sync)
|
||||
{
|
||||
#ifndef NO_TABLE_WIN32_LOCKING
|
||||
if (!is_sync && fl->cached)
|
||||
return;
|
||||
|
||||
if (--fl->locks == 0)
|
||||
{
|
||||
if (fl && fl->lockFile && fl->lockFile != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
fclose(fl->lockFile);
|
||||
unlink(fl->lockname);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
66
Src/nde/osx/Vfs.h
Normal file
66
Src/nde/osx/Vfs.h
Normal file
|
@ -0,0 +1,66 @@
|
|||
#ifndef __NDE_VFS_H
|
||||
#define __NDE_VFS_H
|
||||
|
||||
#include <bfc/platform/types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
//#define NDE_ALLOW_NONCACHED
|
||||
|
||||
/*
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
#ifndef NDE_NOWIN32FILEIO
|
||||
#error NDE_ALLOW_NONCACHED at least for now requires NDE_NOWIN32FILEIO
|
||||
#endif
|
||||
#endif
|
||||
*/
|
||||
|
||||
#define VFILE_INC 65536
|
||||
|
||||
#define VFS_READ 1
|
||||
#define VFS_WRITE 2
|
||||
#define VFS_SEEKEOF 4
|
||||
#define VFS_CREATE 8
|
||||
#define VFS_NEWCONTENT 16
|
||||
#define VFS_MUSTEXIST 32
|
||||
|
||||
typedef struct {
|
||||
uint8_t *data;
|
||||
unsigned long ptr;
|
||||
unsigned long filesize;
|
||||
unsigned long maxsize;
|
||||
char *filename;
|
||||
char mode;
|
||||
BOOL cached;
|
||||
int dirty;
|
||||
|
||||
#ifdef NDE_ALLOW_NONCACHED
|
||||
FILE *rfile;
|
||||
#endif
|
||||
FILE *lockFile;
|
||||
char lockname[1024];
|
||||
int locks;
|
||||
} VFILE;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
VFILE *Vfnew(const char *fl, const char *mode, BOOL Cached);
|
||||
VFILE *Vfopen(VFILE *f, const char *fl, const char *mode, BOOL Cached);
|
||||
size_t Vfread(void *ptr, size_t size, VFILE *buf);
|
||||
void Vfseek(VFILE *fl, long i, int whence);
|
||||
unsigned long Vftell(VFILE *fl);
|
||||
void Vfclose(VFILE *fl);
|
||||
void Vfdestroy(VFILE *fl); // benski> TODO:
|
||||
void Vfwrite(const void *ptr, size_t size, VFILE *f);
|
||||
int Vfeof(VFILE *fl);
|
||||
int Vsync(VFILE *fl); // 1 on error updating
|
||||
int Vflock(VFILE *fl, BOOL is_sync=TRUE); // returns 0 on failure
|
||||
void Vfunlock(VFILE *fl, BOOL is_sync=TRUE);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
640
Src/nde/osx/nde_c.cpp
Normal file
640
Src/nde/osx/nde_c.cpp
Normal file
|
@ -0,0 +1,640 @@
|
|||
#include "nde_c.h"
|
||||
#include "nde.h"
|
||||
#ifdef _WIN32
|
||||
#include "../nu/AutoCharFn.h"
|
||||
#include "../nu/AutoWide.h"
|
||||
#endif
|
||||
|
||||
/* Database */
|
||||
#ifdef _WIN32
|
||||
nde_database_t NDE_CreateDatabase(HINSTANCE hInstance)
|
||||
{
|
||||
return (nde_database_t)new Database(hInstance);
|
||||
}
|
||||
#else
|
||||
nde_database_t NDE_CreateDatabase()
|
||||
{
|
||||
return (nde_database_t)new Database();
|
||||
}
|
||||
#endif
|
||||
|
||||
void NDE_DestroyDatabase(nde_database_t db)
|
||||
{
|
||||
delete (Database *)db;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
nde_table_t NDE_Database_OpenTable(nde_database_t db, const wchar_t *filename, const wchar_t *indexname, int create, int cache)
|
||||
{
|
||||
Database *database = (Database *)db;
|
||||
if (database && filename)
|
||||
return (nde_table_t)database->OpenTable(filename, indexname, (BOOL)create, (BOOL)cache);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
nde_table_t NDE_Database_OpenTable(nde_database_t db, const char *filename, const char *indexname, int create, int cache)
|
||||
{
|
||||
Database *database = (Database *)db;
|
||||
if (database && filename)
|
||||
return (nde_table_t)database->OpenTable(filename, indexname, (BOOL)create, (BOOL)cache);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void NDE_Database_CloseTable(nde_database_t db, nde_table_t t)
|
||||
{
|
||||
Database *database = (Database *)db;
|
||||
Table *table = (Table *)t;
|
||||
if (database && table)
|
||||
{
|
||||
database->CloseTable(table);
|
||||
}
|
||||
}
|
||||
/* Table */
|
||||
|
||||
#ifdef _WIN32
|
||||
nde_field_t NDE_Table_NewColumn(nde_table_t t, unsigned char id, const char *name, unsigned char type)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
return (nde_field_t)table->NewColumn(id, AutoWide(name), type, FALSE);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
nde_field_t NDE_Table_NewColumn(nde_table_t t, unsigned char id, CFStringRef name, unsigned char type)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
return (nde_field_t)table->NewColumn(id, name, type, FALSE);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void NDE_Table_PostColumns(nde_table_t t)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
table->PostColumns();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void NDE_Table_AddIndexByID(nde_table_t t, unsigned char id, const char *name)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
table->AddIndexById(id, AutoWide(name));
|
||||
}
|
||||
#else
|
||||
void NDE_Table_AddIndexByID(nde_table_t t, unsigned char id, CFStringRef name)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
table->AddIndexById(id, name);
|
||||
}
|
||||
#endif
|
||||
|
||||
nde_scanner_t NDE_Table_CreateScanner(nde_table_t t)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
return (nde_scanner_t)table->NewScanner();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NDE_Table_DestroyScanner(nde_table_t t, nde_scanner_t s)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (table && scanner)
|
||||
table->DeleteScanner(scanner);
|
||||
}
|
||||
|
||||
void NDE_Table_Sync(nde_table_t t)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
table->Sync();
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void NDE_Table_Compact(nde_table_t t, int *progress)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
table->Compact(progress);
|
||||
}
|
||||
#endif
|
||||
|
||||
int NDE_Table_GetRecordsCount(nde_table_t t)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
return table->GetRecordsCount();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
nde_field_t NDE_Table_GetColumnByID(nde_table_t t, unsigned char id)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
return (nde_field_t)table->GetColumnById(id);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
nde_field_t NDE_Table_GetColumnByName(nde_table_t t, const char *name)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table && name)
|
||||
return (nde_field_t)table->GetColumnByName(AutoWide(name));
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
nde_field_t NDE_Table_GetColumnByName(nde_table_t t, CFStringRef name)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table && name)
|
||||
return (nde_field_t)table->GetColumnByName(name);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void NDE_Table_SetColumnSearchableByID(nde_table_t t, unsigned char id, int searchable)
|
||||
{
|
||||
Table *table = (Table *)t;
|
||||
if (table)
|
||||
table->SetFieldSearchableById(id, !!searchable);
|
||||
}
|
||||
/* Scanner */
|
||||
#ifdef _WIN32
|
||||
int NDE_Scanner_Query(nde_scanner_t s, const wchar_t *query)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return scanner->Query(query);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NDE_Scanner_Search(nde_scanner_t s, const wchar_t *search_term)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
scanner->Search(search_term);
|
||||
}
|
||||
|
||||
const wchar_t *NDE_Scanner_GetLastQuery(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return scanner->GetLastQuery();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
int NDE_Scanner_Query(nde_scanner_t s, const char *query)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return scanner->Query(query);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
CFStringRef NDE_Scanner_GetLastQuery(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return scanner->GetLastQuery();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int NDE_Scanner_GetRecordsCount(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return scanner->GetRecordsCount();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NDE_Scanner_New(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
scanner->New();
|
||||
}
|
||||
|
||||
void NDE_Scanner_Post(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
scanner->Post();
|
||||
}
|
||||
|
||||
void NDE_Scanner_First(nde_scanner_t s, int *killswitch)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
scanner->First(killswitch);
|
||||
}
|
||||
|
||||
void NDE_Scanner_Delete(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
scanner->Delete();
|
||||
}
|
||||
|
||||
void NDE_Scanner_Edit(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
scanner->Edit();
|
||||
}
|
||||
|
||||
int NDE_Scanner_EOF(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return scanner->Eof();
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
int NDE_Scanner_BOF(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return scanner->Bof();
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
nde_field_t NDE_Scanner_NewFieldByID(nde_scanner_t s, unsigned char id)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return (nde_field_t)scanner->NewFieldById(id, PERM_READWRITE);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
nde_field_t NDE_Scanner_NewFieldByName(nde_scanner_t s, const char *name)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return (nde_field_t)scanner->NewFieldByName(AutoWide(name), PERM_READWRITE);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
nde_field_t NDE_Scanner_NewFieldByName(nde_scanner_t s, CFStringRef name)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return (nde_field_t)scanner->NewFieldByName(name, PERM_READWRITE);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
nde_field_t NDE_Scanner_GetFieldByID(nde_scanner_t s, unsigned char id)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return (nde_field_t)scanner->GetFieldById(id);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
nde_field_t NDE_Scanner_GetFieldByName(nde_scanner_t s, const char *name)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner && name)
|
||||
return (nde_field_t)scanner->GetFieldByName(AutoWide(name));
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
nde_field_t NDE_Scanner_GetFieldByName(nde_scanner_t s, CFStringRef name)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner && name)
|
||||
return (nde_field_t)scanner->GetFieldByName(name);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void NDE_Scanner_AddFilterByID(nde_scanner_t s, unsigned char id, nde_field_t f, unsigned char filter_operation)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
Field *field = (Field *)f;
|
||||
if (scanner && field)
|
||||
scanner->AddFilterById(id, field, filter_operation);
|
||||
}
|
||||
|
||||
int NDE_Scanner_LocateInteger(nde_scanner_t s, unsigned char id, int from, int value, int *nskip, int compare_mode)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
{
|
||||
IntegerField field(value);
|
||||
return scanner->LocateByIdEx(id, from, &field, nskip, compare_mode);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
int NDE_Scanner_LocateString(nde_scanner_t s, unsigned char id, int from, const wchar_t *value, int *nskip, int compare_mode)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
{
|
||||
StringField field(value);
|
||||
return scanner->LocateByIdEx(id, from, &field, nskip, compare_mode);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int NDE_Scanner_LocateNDEString(nde_scanner_t s, unsigned char id, int from, wchar_t *value, int *nskip, int compare_mode)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
{
|
||||
StringField field(value, STRING_IS_NDESTRING);
|
||||
return scanner->LocateByIdEx(id, from, &field, nskip, compare_mode);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
int NDE_Scanner_LocateFilename(nde_scanner_t s, unsigned char id, int from, const wchar_t *value, int *nskip, int compare_mode)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
{
|
||||
FilenameField field(value);
|
||||
return scanner->LocateByIdEx(id, from, &field, nskip, compare_mode);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int NDE_Scanner_LocateNDEFilename(nde_scanner_t s, unsigned char id, int from, wchar_t *value, int *nskip, int compare_mode)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
{
|
||||
FilenameField field(value, STRING_IS_NDESTRING);
|
||||
return scanner->LocateByIdEx(id, from, &field, nskip, compare_mode);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int NDE_Scanner_LocateField(nde_scanner_t s, unsigned char id, int from, nde_field_t f, int *nskip, int compare_mode)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
Field *field = (Field *)f;
|
||||
if (scanner && field)
|
||||
{
|
||||
return scanner->LocateByIdEx(id, from, field, nskip, compare_mode);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void NDE_Scanner_DeleteField(nde_scanner_t s, nde_field_t f)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
Field *field = (Field *)f;
|
||||
if (scanner && field)
|
||||
{
|
||||
scanner->DeleteField(field);
|
||||
}
|
||||
}
|
||||
|
||||
void NDE_Scanner_RemoveFilters(nde_scanner_t s)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
scanner->RemoveFilters();
|
||||
}
|
||||
|
||||
int NDE_Scanner_Next(nde_scanner_t s, int *killswitch)
|
||||
{
|
||||
Scanner *scanner = (Scanner *)s;
|
||||
if (scanner)
|
||||
return scanner->Next(killswitch);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
/* Filter functions */
|
||||
unsigned char NDE_Filter_GetID(nde_filter_t f)
|
||||
{
|
||||
Filter *filter = (Filter *)f;
|
||||
if (filter)
|
||||
return filter->GetId();
|
||||
else
|
||||
return FILTERS_INVALID; // right value but I'm not sure if it's the best constant name to use
|
||||
}
|
||||
|
||||
NDE_API unsigned char NDE_Filter_GetOp(nde_filter_t f)
|
||||
{
|
||||
Filter *filter = (Filter *)f;
|
||||
if (filter)
|
||||
return filter->GetOp();
|
||||
else
|
||||
return FILTERS_INVALID; // right value but I'm not sure if it's the best constant name to use
|
||||
}
|
||||
|
||||
NDE_API nde_field_t NDE_Filter_GetData(nde_filter_t f)
|
||||
{
|
||||
Filter *filter = (Filter *)f;
|
||||
if (filter)
|
||||
return (nde_field_t)filter->Data();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Field functions */
|
||||
unsigned char NDE_Field_GetType(nde_field_t f)
|
||||
{
|
||||
Field *field = (Field *)f;
|
||||
if (field)
|
||||
return field->GetType();
|
||||
else
|
||||
return FIELD_UNKNOWN;
|
||||
}
|
||||
|
||||
unsigned char NDE_Field_GetID(nde_field_t f)
|
||||
{
|
||||
Field *field = (Field *)f;
|
||||
if (field)
|
||||
return field->GetFieldId();
|
||||
else
|
||||
return FIELD_UNKNOWN;
|
||||
}
|
||||
|
||||
/* StringField functions */
|
||||
#ifdef _WIN32
|
||||
void NDE_StringField_SetNDEString(nde_field_t f, wchar_t *nde_string)
|
||||
{
|
||||
StringField *field = (StringField *)(Field *)f;
|
||||
if (field)
|
||||
field->SetNDEString(nde_string);
|
||||
}
|
||||
|
||||
wchar_t *NDE_StringField_GetString(nde_field_t f)
|
||||
{
|
||||
StringField *field = (StringField *)(Field *)f;
|
||||
if (field)
|
||||
return field->GetStringW();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void NDE_StringField_SetString(nde_field_t f, const wchar_t *str)
|
||||
{
|
||||
StringField *field = (StringField *)(Field *)f;
|
||||
if (field)
|
||||
field->SetStringW(str);
|
||||
}
|
||||
#endif
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
void NDE_StringField_SetString(nde_field_t f, CFStringRef nde_string)
|
||||
{
|
||||
StringField *field = (StringField *)(Field *)f;
|
||||
if (field)
|
||||
field->SetNDEString(nde_string);
|
||||
}
|
||||
|
||||
CFStringRef NDE_StringField_GetString(nde_field_t f)
|
||||
{
|
||||
StringField *field = (StringField *)(Field *)f;
|
||||
if (field)
|
||||
return field->GetString();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* IntegerField functions */
|
||||
void NDE_IntegerField_SetValue(nde_field_t f, int value)
|
||||
{
|
||||
IntegerField *field = (IntegerField *)(Field *)f;
|
||||
if (field)
|
||||
field->SetValue(value);
|
||||
}
|
||||
|
||||
int NDE_IntegerField_GetValue(nde_field_t f)
|
||||
{
|
||||
IntegerField *field = (IntegerField *)(Field *)f;
|
||||
if (field)
|
||||
return field->GetValue();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
nde_field_t NDE_IntegerField_Create(int value)
|
||||
{
|
||||
return (nde_field_t)new IntegerField(value);
|
||||
}
|
||||
|
||||
/* BinaryField */
|
||||
void *NDE_BinaryField_GetData(nde_field_t f, size_t *length)
|
||||
{
|
||||
BinaryField *field = (BinaryField *)(Field *)f;
|
||||
if (field)
|
||||
return (void *)field->GetData(length);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
CFDataRef NDE_BinaryField_GetCFData(nde_field_t f)
|
||||
{
|
||||
BinaryField *field = (BinaryField *)(Field *)f;
|
||||
if (field)
|
||||
return field->GetCFData();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
void NDE_BinaryField_SetData(nde_field_t f, const void *data, size_t length)
|
||||
{
|
||||
BinaryField *field = (BinaryField *)(Field *)f;
|
||||
if (field)
|
||||
field->SetData((const uint8_t *)data, length);
|
||||
}
|
||||
|
||||
/* Int128Field */
|
||||
void NDE_Int128Field_SetValue(nde_field_t f, const void *value)
|
||||
{
|
||||
Int128Field *field = (Int128Field *)(Field *)f;
|
||||
if (field && value)
|
||||
field->SetValue(value);
|
||||
}
|
||||
|
||||
/* ColumnField */
|
||||
#ifdef _WIN32
|
||||
const wchar_t *NDE_ColumnField_GetFieldName(nde_field_t f)
|
||||
{
|
||||
ColumnField *field = (ColumnField *)(Field *)f;
|
||||
if (field)
|
||||
return field->GetFieldName();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
CFStringRef NDE_ColumnField_GetFieldName(nde_field_t f)
|
||||
{
|
||||
ColumnField *field = (ColumnField *)(Field *)f;
|
||||
if (field)
|
||||
return field->GetFieldName();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
unsigned char NDE_ColumnField_GetDataType(nde_field_t f)
|
||||
{
|
||||
ColumnField *field = (ColumnField *)(Field *)f;
|
||||
if (field)
|
||||
return field->GetDataType();
|
||||
else
|
||||
return FIELD_UNKNOWN;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
__time64_t NDE_Time_ApplyConversion(__time64_t value, const wchar_t *str, class TimeParse *tp)
|
||||
{
|
||||
IntegerField f(value);
|
||||
f.ApplyConversion(str, tp);
|
||||
return f.GetValue();
|
||||
}
|
||||
#endif
|
246
Src/nde/osx/nde_c.h
Normal file
246
Src/nde/osx/nde_c.h
Normal file
|
@ -0,0 +1,246 @@
|
|||
#pragma once
|
||||
/* C style API.
|
||||
|
||||
We'll eventually deprecate the C++ API as it presents a lot of linking challenges
|
||||
*/
|
||||
#include "nde_defines.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "NDEString.h"
|
||||
#include <bfc/platform/types.h>
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
typedef time_t __time64_t; // TODO: find a way to do native 64bit time values
|
||||
#endif
|
||||
typedef struct nde_database_struct_t { } *nde_database_t;
|
||||
typedef struct nde_table_struct_t { } *nde_table_t;
|
||||
typedef struct nde_scanner_t_struct_t { } *nde_scanner_t;
|
||||
typedef struct nde_field_t_struct_t { } *nde_field_t;
|
||||
typedef struct nde_filter_struct_t { } *nde_filter_t;
|
||||
|
||||
/* Database functions */
|
||||
|
||||
// Windows API
|
||||
#ifdef _WIN32
|
||||
NDE_API void NDE_Init();
|
||||
NDE_API void NDE_Quit();
|
||||
#ifdef __cplusplus
|
||||
NDE_API nde_database_t NDE_CreateDatabase(HINSTANCE hInstance=0);
|
||||
#else
|
||||
NDE_API nde_database_t NDE_CreateDatabase(HINSTANCE hInstance);
|
||||
#endif
|
||||
NDE_API void NDE_DestroyDatabase(nde_database_t db);
|
||||
NDE_API nde_table_t NDE_Database_OpenTable(nde_database_t db, const wchar_t *filename, const wchar_t *filename_index, int create, int cache);
|
||||
|
||||
NDE_API void NDE_Database_CloseTable(nde_database_t db, nde_table_t table);
|
||||
|
||||
/* Table functions */
|
||||
NDE_API nde_field_t NDE_Table_NewColumn(nde_table_t table, unsigned char id, const char *name, unsigned char type);
|
||||
NDE_API void NDE_Table_PostColumns(nde_table_t table);
|
||||
NDE_API void NDE_Table_AddIndexByID(nde_table_t table, unsigned char id, const char *name);
|
||||
NDE_API nde_scanner_t NDE_Table_CreateScanner(nde_table_t table);
|
||||
NDE_API void NDE_Table_DestroyScanner(nde_table_t table, nde_scanner_t scanner);
|
||||
NDE_API void NDE_Table_Sync(nde_table_t table);
|
||||
#ifdef __cplusplus
|
||||
NDE_API void NDE_Table_Compact(nde_table_t table, int *progress=0);
|
||||
#else
|
||||
NDE_API void NDE_Table_Compact(nde_table_t table, int *progress);
|
||||
#endif
|
||||
NDE_API int NDE_Table_GetRecordsCount(nde_table_t table);
|
||||
NDE_API nde_field_t NDE_Table_GetColumnByID(nde_table_t table, unsigned char id);
|
||||
#ifdef _WIN32
|
||||
NDE_API nde_field_t NDE_Table_GetColumnByName(nde_table_t table, const char *name);
|
||||
#else
|
||||
NDE_API nde_field_t NDE_Table_GetColumnByName(nde_table_t table, CFStringRef name);
|
||||
#endif
|
||||
NDE_API void NDE_Table_SetColumnSearchableByID(nde_table_t table, unsigned char id, int searchable);
|
||||
|
||||
/* Scanner functions */
|
||||
NDE_API int NDE_Scanner_Query(nde_scanner_t scanner, const wchar_t *query);
|
||||
NDE_API void NDE_Scanner_Search(nde_scanner_t scanner, const wchar_t *search_term);
|
||||
NDE_API const wchar_t *NDE_Scanner_GetLastQuery(nde_scanner_t scanner);
|
||||
NDE_API int NDE_Scanner_GetRecordsCount(nde_scanner_t scanner);
|
||||
NDE_API void NDE_Scanner_New(nde_scanner_t scanner);
|
||||
NDE_API void NDE_Scanner_Post(nde_scanner_t scanner);
|
||||
#ifdef __cplusplus
|
||||
NDE_API void NDE_Scanner_First(nde_scanner_t scanner, int *killswitch=0);
|
||||
NDE_API int NDE_Scanner_Next(nde_scanner_t scanner, int *killswitch=0);
|
||||
#else
|
||||
NDE_API void NDE_Scanner_First(nde_scanner_t scanner, int *killswitch);
|
||||
NDE_API int NDE_Scanner_Next(nde_scanner_t scanner, int *killswitch);
|
||||
#endif
|
||||
NDE_API void NDE_Scanner_Delete(nde_scanner_t scanner);
|
||||
NDE_API void NDE_Scanner_Edit(nde_scanner_t scanner);
|
||||
NDE_API int NDE_Scanner_EOF(nde_scanner_t scanner);
|
||||
NDE_API int NDE_Scanner_BOF(nde_scanner_t scanner);
|
||||
NDE_API nde_field_t NDE_Scanner_NewFieldByID(nde_scanner_t scanner, unsigned char id);
|
||||
NDE_API nde_field_t NDE_Scanner_NewFieldByName(nde_scanner_t scanner, const char *name);
|
||||
NDE_API nde_field_t NDE_Scanner_GetFieldByID(nde_scanner_t scanner, unsigned char id);
|
||||
NDE_API nde_field_t NDE_Scanner_GetFieldByName(nde_scanner_t scanner, const char *name);
|
||||
NDE_API void NDE_Scanner_AddFilterByID(nde_scanner_t scanner, unsigned char id, nde_field_t field, unsigned char filter_operation);
|
||||
#ifdef __cplusplus
|
||||
NDE_API int NDE_Scanner_LocateInteger(nde_scanner_t scanner, unsigned char id, int from, int value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
|
||||
NDE_API int NDE_Scanner_LocateString(nde_scanner_t scanner, unsigned char id, int from, const wchar_t *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
|
||||
NDE_API int NDE_Scanner_LocateNDEString(nde_scanner_t scanner, unsigned char id, int from, wchar_t *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
|
||||
NDE_API int NDE_Scanner_LocateFilename(nde_scanner_t scanner, unsigned char id, int from, const wchar_t *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
|
||||
NDE_API int NDE_Scanner_LocateNDEFilename(nde_scanner_t scanner, unsigned char id, int from, wchar_t *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
|
||||
NDE_API int NDE_Scanner_LocateField(nde_scanner_t scanner, unsigned char id, int from, nde_field_t field, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
|
||||
#else
|
||||
NDE_API int NDE_Scanner_LocateInteger(nde_scanner_t scanner, unsigned char id, int from, int value, int *nskip, int compare_mode);
|
||||
NDE_API int NDE_Scanner_LocateString(nde_scanner_t scanner, unsigned char id, int from, const wchar_t *value, int *nskip, int compare_mode);
|
||||
NDE_API int NDE_Scanner_LocateNDEString(nde_scanner_t scanner, unsigned char id, int from, wchar_t *value, int *nskip, int compare_mode);
|
||||
NDE_API int NDE_Scanner_LocateFilename(nde_scanner_t scanner, unsigned char id, int from, const wchar_t *value, int *nskip, int compare_mode);
|
||||
NDE_API int NDE_Scanner_LocateNDEFilename(nde_scanner_t scanner, unsigned char id, int from, wchar_t *value, int *nskip, int compare_mode);
|
||||
NDE_API int NDE_Scanner_LocateField(nde_scanner_t scanner, unsigned char id, int from, nde_field_t field, int *nskip, int compare_mode);
|
||||
#endif
|
||||
NDE_API void NDE_Scanner_DeleteField(nde_scanner_t scanner, nde_field_t field);
|
||||
NDE_API void NDE_Scanner_RemoveFilters(nde_scanner_t scanner);
|
||||
|
||||
/* Filter functions */
|
||||
NDE_API unsigned char NDE_Filter_GetID(nde_filter_t filter);
|
||||
NDE_API unsigned char NDE_Filter_GetOp(nde_filter_t filter);
|
||||
NDE_API nde_field_t NDE_Filter_GetData(nde_filter_t filter);
|
||||
|
||||
/* Field functions */
|
||||
NDE_API unsigned char NDE_Field_GetType(nde_field_t field);
|
||||
NDE_API unsigned char NDE_Field_GetID(nde_field_t field);
|
||||
|
||||
/* String Field functions */
|
||||
NDE_API wchar_t *NDE_StringField_GetString(nde_field_t field); /* returns non-const because it's an NDE string (reference counted, see ndestring.h) */
|
||||
NDE_API void NDE_StringField_SetNDEString(nde_field_t field, wchar_t *nde_string);
|
||||
NDE_API void NDE_StringField_SetString(nde_field_t field, const wchar_t *str);
|
||||
|
||||
/* IntegerField functions */
|
||||
NDE_API void NDE_IntegerField_SetValue(nde_field_t field, int value);
|
||||
NDE_API int NDE_IntegerField_GetValue(nde_field_t field);
|
||||
NDE_API nde_field_t NDE_IntegerField_Create(int value); /* mainly used for NDE_Scanner_AddFilterByID */
|
||||
|
||||
/* BinaryField functions */
|
||||
// on windows, the data pointer is optionally reference counted via ndestring (ndestring_retain if you plan on keeping it)
|
||||
NDE_API void *NDE_BinaryField_GetData(nde_field_t field, size_t *length);
|
||||
NDE_API void NDE_BinaryField_SetData(nde_field_t field, const void *data, size_t length);
|
||||
|
||||
/* Int128Field functions */
|
||||
NDE_API void NDE_Int128Field_SetValue(nde_field_t field, const void *value);
|
||||
|
||||
/* ColumnField functions */
|
||||
NDE_API const wchar_t *NDE_ColumnField_GetFieldName(nde_field_t field);
|
||||
NDE_API unsigned char NDE_ColumnField_GetDataType(nde_field_t field);
|
||||
|
||||
NDE_API __time64_t NDE_Time_ApplyConversion(__time64_t value, const wchar_t *str, class TimeParse *tp);
|
||||
#elif defined(__APPLE__) // Mac OS X API, uses CFStringRef for a lot of stuff
|
||||
NDE_API void NDE_Init();
|
||||
NDE_API void NDE_Quit();
|
||||
NDE_API nde_database_t NDE_CreateDatabase();
|
||||
|
||||
NDE_API void NDE_DestroyDatabase(nde_database_t db);
|
||||
NDE_API nde_table_t NDE_Database_OpenTable(nde_database_t db, const char *filename, const char *filename_index, int create, int cache);
|
||||
NDE_API void NDE_Database_CloseTable(nde_database_t db, nde_table_t table);
|
||||
|
||||
/* Table functions */
|
||||
NDE_API nde_field_t NDE_Table_NewColumn(nde_table_t table, unsigned char id, const char *name, unsigned char type);
|
||||
NDE_API void NDE_Table_PostColumns(nde_table_t table);
|
||||
NDE_API void NDE_Table_AddIndexByID(nde_table_t table, unsigned char id, const char *name);
|
||||
NDE_API nde_scanner_t NDE_Table_CreateScanner(nde_table_t table);
|
||||
NDE_API void NDE_Table_DestroyScanner(nde_table_t table, nde_scanner_t scanner);
|
||||
NDE_API void NDE_Table_Sync(nde_table_t table);
|
||||
#ifdef __cplusplus
|
||||
NDE_API void NDE_Table_Compact(nde_table_t table, int *progress=0);
|
||||
#else
|
||||
NDE_API void NDE_Table_Compact(nde_table_t table, int *progress);
|
||||
#endif
|
||||
NDE_API int NDE_Table_GetRecordsCount(nde_table_t table);
|
||||
NDE_API nde_field_t NDE_Table_GetColumnByID(nde_table_t table, unsigned char id);
|
||||
#ifdef _WIN32
|
||||
NDE_API nde_field_t NDE_Table_GetColumnByName(nde_table_t table, const char *name);
|
||||
#else
|
||||
NDE_API nde_field_t NDE_Table_GetColumnByName(nde_table_t table, CFStringRef name);
|
||||
#endif
|
||||
|
||||
/* Scanner functions */
|
||||
NDE_API int NDE_Scanner_Query(nde_scanner_t scanner, const wchar_t *query);
|
||||
NDE_API CFStringRef NDE_Scanner_GetLastQuery(nde_scanner_t scanner);
|
||||
NDE_API int NDE_Scanner_GetRecordsCount(nde_scanner_t scanner);
|
||||
NDE_API void NDE_Scanner_New(nde_scanner_t scanner);
|
||||
NDE_API void NDE_Scanner_Post(nde_scanner_t scanner);
|
||||
#ifdef __cplusplus
|
||||
NDE_API void NDE_Scanner_First(nde_scanner_t scanner, int *killswitch=0);
|
||||
NDE_API int NDE_Scanner_Next(nde_scanner_t scanner, int *killswitch=0);
|
||||
#else
|
||||
NDE_API void NDE_Scanner_First(nde_scanner_t scanner, int *killswitch);
|
||||
NDE_API int NDE_Scanner_Next(nde_scanner_t scanner, int *killswitch);
|
||||
#endif
|
||||
NDE_API void NDE_Scanner_Delete(nde_scanner_t scanner);
|
||||
NDE_API void NDE_Scanner_Edit(nde_scanner_t scanner);
|
||||
NDE_API int NDE_Scanner_EOF(nde_scanner_t scanner);
|
||||
NDE_API int NDE_Scanner_BOF(nde_scanner_t scanner);
|
||||
NDE_API nde_field_t NDE_Scanner_NewFieldByID(nde_scanner_t scanner, unsigned char id);
|
||||
NDE_API nde_field_t NDE_Scanner_NewFieldByName(nde_scanner_t scanner, const char *name);
|
||||
NDE_API nde_field_t NDE_Scanner_GetFieldByID(nde_scanner_t scanner, unsigned char id);
|
||||
NDE_API nde_field_t NDE_Scanner_GetFieldByName(nde_scanner_t scanner, const char *name);
|
||||
NDE_API void NDE_Scanner_AddFilterByID(nde_scanner_t scanner, unsigned char id, nde_field_t field, unsigned char filter_operation);
|
||||
#ifdef __cplusplus
|
||||
NDE_API int NDE_Scanner_LocateInteger(nde_scanner_t scanner, unsigned char id, int from, int value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
|
||||
NDE_API int NDE_Scanner_LocateString(nde_scanner_t scanner, unsigned char id, int from, const wchar_t *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
|
||||
NDE_API int NDE_Scanner_LocateNDEString(nde_scanner_t scanner, unsigned char id, int from, wchar_t *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
|
||||
NDE_API int NDE_Scanner_LocateFilename(nde_scanner_t scanner, unsigned char id, int from, const wchar_t *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
|
||||
NDE_API int NDE_Scanner_LocateNDEFilename(nde_scanner_t scanner, unsigned char id, int from, wchar_t *value, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
|
||||
NDE_API int NDE_Scanner_LocateField(nde_scanner_t scanner, unsigned char id, int from, nde_field_t field, int *nskip=0, int compare_mode=COMPARE_MODE_EXACT);
|
||||
#else
|
||||
NDE_API int NDE_Scanner_LocateInteger(nde_scanner_t scanner, unsigned char id, int from, int value, int *nskip, int compare_mode);
|
||||
NDE_API int NDE_Scanner_LocateString(nde_scanner_t scanner, unsigned char id, int from, const wchar_t *value, int *nskip, int compare_mode);
|
||||
NDE_API int NDE_Scanner_LocateNDEString(nde_scanner_t scanner, unsigned char id, int from, wchar_t *value, int *nskip, int compare_mode);
|
||||
NDE_API int NDE_Scanner_LocateFilename(nde_scanner_t scanner, unsigned char id, int from, const wchar_t *value, int *nskip, int compare_mode);
|
||||
NDE_API int NDE_Scanner_LocateNDEFilename(nde_scanner_t scanner, unsigned char id, int from, wchar_t *value, int *nskip, int compare_mode);
|
||||
NDE_API int NDE_Scanner_LocateField(nde_scanner_t scanner, unsigned char id, int from, nde_field_t field, int *nskip, int compare_mode);
|
||||
#endif
|
||||
NDE_API void NDE_Scanner_DeleteField(nde_scanner_t scanner, nde_field_t field);
|
||||
NDE_API void NDE_Scanner_RemoveFilters(nde_scanner_t scanner);
|
||||
|
||||
/* Filter functions */
|
||||
NDE_API unsigned char NDE_Filter_GetID(nde_filter_t filter);
|
||||
NDE_API unsigned char NDE_Filter_GetOp(nde_filter_t filter);
|
||||
NDE_API nde_field_t NDE_Filter_GetData(nde_filter_t filter);
|
||||
|
||||
/* Field functions */
|
||||
NDE_API unsigned char NDE_Field_GetType(nde_field_t field);
|
||||
NDE_API unsigned char NDE_Field_GetID(nde_field_t field);
|
||||
|
||||
/* String Field functions */
|
||||
|
||||
NDE_API CFStringRef NDE_StringField_GetString(nde_field_t field); /* returns non-const because it's an NDE string (reference counted, see ndestring.h) */
|
||||
NDE_API void NDE_StringField_SetString(nde_field_t field, CFStringRef string);
|
||||
|
||||
/* IntegerField functions */
|
||||
NDE_API void NDE_IntegerField_SetValue(nde_field_t field, int value);
|
||||
NDE_API int NDE_IntegerField_GetValue(nde_field_t field);
|
||||
NDE_API nde_field_t NDE_IntegerField_Create(int value); /* mainly used for NDE_Scanner_AddFilterByID */
|
||||
|
||||
/* BinaryField functions */
|
||||
NDE_API void *NDE_BinaryField_GetData(nde_field_t field, size_t *length);
|
||||
NDE_API CFDataRef NDE_BinaryField_GetCFData(nde_field_t field);
|
||||
NDE_API void NDE_BinaryField_SetData(nde_field_t field, const void *data, size_t length);
|
||||
|
||||
/* Int128Field functions */
|
||||
NDE_API void NDE_Int128Field_SetValue(nde_field_t field, const void *value);
|
||||
|
||||
/* ColumnField functions */
|
||||
#ifdef _WIN32
|
||||
NDE_API const char *NDE_ColumnField_GetFieldName(nde_field_t field);
|
||||
#else
|
||||
NDE_API CFStringRef NDE_ColumnField_GetFieldName(nde_field_t field);
|
||||
#endif
|
||||
NDE_API unsigned char NDE_ColumnField_GetDataType(nde_field_t field);
|
||||
|
||||
NDE_API __time64_t NDE_Time_ApplyConversion(__time64_t value, const wchar_t *str, class TimeParse *tp);
|
||||
#endif
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue