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