winamp/Src/nde/DBUtils.cpp
2024-09-24 14:54:57 +02:00

573 lines
14 KiB
C++

/* ---------------------------------------------------------------------------
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