aboutsummaryrefslogtreecommitdiff
path: root/Src/nde/win/StringField.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/nde/win/StringField.cpp')
-rw-r--r--Src/nde/win/StringField.cpp341
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;
+}