diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/nde/win/StringField.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/nde/win/StringField.cpp')
-rw-r--r-- | Src/nde/win/StringField.cpp | 341 |
1 files changed, 341 insertions, 0 deletions
diff --git a/Src/nde/win/StringField.cpp b/Src/nde/win/StringField.cpp new file mode 100644 index 00000000..b6ae3eed --- /dev/null +++ b/Src/nde/win/StringField.cpp @@ -0,0 +1,341 @@ +/* --------------------------------------------------------------------------- +Nullsoft Database Engine +-------------------- +codename: Near Death Experience +--------------------------------------------------------------------------- */ + +/* --------------------------------------------------------------------------- + +StringField Class +Windows 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" +#include "../../nu/AutoChar.h" +#include "../../nu/AutoWide.h" + +static wchar_t CharSwap(wchar_t value) +{ + return (value >> 8) | (value << 8); +} + +//--------------------------------------------------------------------------- +StringField::StringField(const wchar_t *Str, int strkind) +{ + InitField(); + Type = FIELD_STRING; + if (Str) + { + if (strkind == STRING_IS_WCHAR) + StringW = ndestring_wcsdup(Str); + else + { + StringW = const_cast<wchar_t *>(Str); + ndestring_retain(StringW); + } + } +} + +//--------------------------------------------------------------------------- +void StringField::InitField(void) +{ + Type = FIELD_STRING; + StringW = NULL; + optimized_the = 0; +} + +//--------------------------------------------------------------------------- +StringField::StringField() +{ + InitField(); +} + +//--------------------------------------------------------------------------- +StringField::~StringField() +{ + ndestring_release(StringW); + StringW=0; +} + +//--------------------------------------------------------------------------- +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; + bool reverseEndian=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) + { + data+=2; + c-=2; + unicode=true; + } + else if (BOM == 0xFFFE) + { + data+=2; + c-=2; + unicode=true; + reverseEndian=true; + } + } + + CHECK_BIN(len, c); + if (unicode) + { + ndestring_release(StringW); + StringW = ndestring_malloc(c+sizeof(wchar_t)); + + memcpy(StringW, data, c); + StringW[c/2]=0; + if (reverseEndian) + { + for (unsigned short i=0;i<c;i++) + StringW[i]=CharSwap(StringW[i]); + } + } + else + { + int len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)data, c, 0, 0); + StringW = ndestring_malloc((len+1)*sizeof(wchar_t)); + MultiByteToWideChar(CP_ACP, 0, (LPCSTR)data, c, StringW, len); + StringW[len]=0; + } + } +} + +//--------------------------------------------------------------------------- +void StringField::WriteTypedData(uint8_t *data, size_t len) +{ + int pos=0; + + if (StringW) + { + unsigned short c = (unsigned short)wcslen(StringW) * sizeof(wchar_t) + 2 /* for BOM */; + // write size + CHECK_SHORT(len); + PUT_SHORT(c); pos+=2; + + // write byte order mark + CHECK_BIN(len, 2); + wchar_t BOM = 0xFEFF; + PUT_BINARY(data, (uint8_t *)&BOM, 2, pos); + pos+=2; + c-=2; + + // write string + CHECK_BIN(len, c); + PUT_BINARY(data, (uint8_t *)StringW, c, pos); + } + else + { + CHECK_SHORT(len); + PUT_SHORT(0); /*pos+=2;*/ + } +} + +//--------------------------------------------------------------------------- +wchar_t *StringField::GetStringW(void) +{ + return StringW; +} + +//--------------------------------------------------------------------------- +void StringField::SetStringW(const wchar_t *Str) +{ + if (!Str) return; + + ndestring_release(StringW); + StringW = NULL; + StringW = ndestring_wcsdup(Str); + optimized_the=0; +} + +//--------------------------------------------------------------------------- +void StringField::SetNDEString(wchar_t *Str) +{ + if (!Str) return; + + // copy and then release, just in case we're copying into ourselves + wchar_t *oldStr = StringW; + StringW = Str; + ndestring_retain(StringW); + ndestring_release(oldStr); + optimized_the=0; +} + +//--------------------------------------------------------------------------- +size_t StringField::GetDataSize(void) +{ + if (StringW) + { + return wcslen(StringW)*2 +2 /*for BOM*/ + 2 /*for byte length*/; + } + else + { + return 2; + } +} + +//--------------------------------------------------------------------------- +int StringField::Compare(Field *Entry) +{ + if (!Entry) return -1; + if (Entry->GetType() != GetType()) return 0; + return mywcsicmp(GetStringW(), ((StringField*)Entry)->GetStringW()); +} + +//--------------------------------------------------------------------------- +int StringField::Starts(Field *Entry) +{ + if (!Entry) return -1; + if (Entry->GetType() != GetType()) return 0; + const wchar_t *p = ((StringField*)Entry)->GetStringW(); + const wchar_t *d = GetStringW(); + if (!d || !p) return 0; + return nde_wcsbegins(d, p); +} + +//--------------------------------------------------------------------------- +int StringField::Contains(Field *Entry) +{ + if (!Entry) return -1; + if (Entry->GetType() != GetType()) return 0; + const wchar_t *p = ((StringField*)Entry)->GetStringW(); + const wchar_t *d = GetStringW(); + if (!d || !p) return 0; + return nde_wcscontains(GetStringW(), ((StringField*)Entry)->GetStringW()); +} + +Field *StringField::Clone(Table *pTable) +{ + StringField *clone = new StringField(StringW, STRING_IS_NDESTRING); + clone->Pos = FIELD_CLONE; + clone->ID = ID; + clone->MaxSizeOnDisk = (uint32_t)GetDataSize(); + return clone; +} + +// todo: make configurable words to skip, as well as trailing whitespace removal +#define IsCharSpaceW(c) (c == L' ' || c == L'\t') +inline bool IsTheW(const wchar_t *str) { if (str && (str[0] == L't' || str[0] == L'T') && (str[1] == L'h' || str[1] == L'H') && (str[2] == L'e' || str[2] == L'E') && (str[3] == L' ')) return true; else return false; } +#define SKIP_THE_AND_WHITESPACEW(x) { wchar_t *save##x=(wchar_t*)x; while (IsCharSpaceW(*x) && *x) x++; if (IsTheW(x)) x+=4; while (IsCharSpaceW(*x)) x++; if (!*x) x=save##x; } + +bool StringField::ApplyFilter(Field *Data, int op) +{ + // TODO: maybe do this? + + if (op == FILTER_ISEMPTY || op == FILTER_ISNOTEMPTY) + { + bool r = (op == FILTER_ISEMPTY); + if (!StringW) + return r; + + if (StringW && StringW[0] == 0) + return r; + + return !r; + } + // + bool r; + StringField *compField = (StringField *)Data; + + const wchar_t *p = compField->GetStringW(); + const wchar_t *d = GetStringW(); + if (!p) + p = L""; + if (!d) + d = L""; + + switch (op) + { + case FILTER_EQUALS: + r = !nde_wcsicmp(d, p); + break; + case FILTER_NOTEQUALS: + r = !!nde_wcsicmp(d, p); + break; + case FILTER_CONTAINS: + r = nde_wcscontains(d, p); + break; + case FILTER_NOTCONTAINS: + r = !nde_wcscontains(d, p); + break; + case FILTER_ABOVE: + r = (bool)(nde_wcsicmp(d, p) > 0); + break; + case FILTER_ABOVEOREQUAL: + r = (bool)(nde_wcsicmp(d, p) >= 0); + break; + case FILTER_BELOW: + r = (bool)(nde_wcsicmp(d, p) < 0); + break; + case FILTER_BELOWOREQUAL: + r = (bool)(nde_wcsicmp(d, p) <= 0); + break; + case FILTER_BEGINS: + r = nde_wcsbegins(d, p); + break; + case FILTER_ENDS: + r = nde_wcsends(d, p); + break; + case FILTER_LIKE: + + 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); + 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 = nde_wcsbegins(d, p); + break; + default: + r = true; + break; + } + return r; +} |