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

293 lines
6.3 KiB
C++

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