StringField.cpp 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. /* ---------------------------------------------------------------------------
  2. Nullsoft Database Engine
  3. --------------------
  4. codename: Near Death Experience
  5. --------------------------------------------------------------------------- */
  6. /* ---------------------------------------------------------------------------
  7. StringField Class
  8. Windows specific version
  9. Field data layout:
  10. [2 bytes] string length (bytes)
  11. [length bytes] String data. UTF-16 data will start with a BOM
  12. --------------------------------------------------------------------------- */
  13. #include "../nde.h"
  14. #include "StringField.h"
  15. #include "../../nu/AutoChar.h"
  16. #include "../../nu/AutoWide.h"
  17. static wchar_t CharSwap(wchar_t value)
  18. {
  19. return (value >> 8) | (value << 8);
  20. }
  21. //---------------------------------------------------------------------------
  22. StringField::StringField(const wchar_t *Str, int strkind)
  23. {
  24. InitField();
  25. Type = FIELD_STRING;
  26. if (Str)
  27. {
  28. if (strkind == STRING_IS_WCHAR)
  29. StringW = ndestring_wcsdup(Str);
  30. else
  31. {
  32. StringW = const_cast<wchar_t *>(Str);
  33. ndestring_retain(StringW);
  34. }
  35. }
  36. }
  37. //---------------------------------------------------------------------------
  38. void StringField::InitField(void)
  39. {
  40. Type = FIELD_STRING;
  41. StringW = NULL;
  42. optimized_the = 0;
  43. }
  44. //---------------------------------------------------------------------------
  45. StringField::StringField()
  46. {
  47. InitField();
  48. }
  49. //---------------------------------------------------------------------------
  50. StringField::~StringField()
  51. {
  52. ndestring_release(StringW);
  53. StringW=0;
  54. }
  55. //---------------------------------------------------------------------------
  56. void StringField::ReadTypedData(const uint8_t *data, size_t len)
  57. {
  58. unsigned short c;
  59. CHECK_SHORT(len);
  60. c = (unsigned short)(data[0]|(data[1]<<8));
  61. data+=2;
  62. if (c)
  63. {
  64. bool unicode=false;
  65. bool reverseEndian=false;
  66. if (c >= 2 // enough room for BOM
  67. && (c % 2) == 0) // can't be unicode if it's not an even multiple of 2
  68. {
  69. wchar_t BOM=0;
  70. memcpy(&BOM, data, 2);
  71. if (BOM == 0xFEFF)
  72. {
  73. data+=2;
  74. c-=2;
  75. unicode=true;
  76. }
  77. else if (BOM == 0xFFFE)
  78. {
  79. data+=2;
  80. c-=2;
  81. unicode=true;
  82. reverseEndian=true;
  83. }
  84. }
  85. CHECK_BIN(len, c);
  86. if (unicode)
  87. {
  88. ndestring_release(StringW);
  89. StringW = ndestring_malloc(c+sizeof(wchar_t));
  90. memcpy(StringW, data, c);
  91. StringW[c/2]=0;
  92. if (reverseEndian)
  93. {
  94. for (unsigned short i=0;i<c;i++)
  95. StringW[i]=CharSwap(StringW[i]);
  96. }
  97. }
  98. else
  99. {
  100. int len = MultiByteToWideChar(CP_ACP, 0, (LPCSTR)data, c, 0, 0);
  101. StringW = ndestring_malloc((len+1)*sizeof(wchar_t));
  102. MultiByteToWideChar(CP_ACP, 0, (LPCSTR)data, c, StringW, len);
  103. StringW[len]=0;
  104. }
  105. }
  106. }
  107. //---------------------------------------------------------------------------
  108. void StringField::WriteTypedData(uint8_t *data, size_t len)
  109. {
  110. int pos=0;
  111. if (StringW)
  112. {
  113. unsigned short c = (unsigned short)wcslen(StringW) * sizeof(wchar_t) + 2 /* for BOM */;
  114. // write size
  115. CHECK_SHORT(len);
  116. PUT_SHORT(c); pos+=2;
  117. // write byte order mark
  118. CHECK_BIN(len, 2);
  119. wchar_t BOM = 0xFEFF;
  120. PUT_BINARY(data, (uint8_t *)&BOM, 2, pos);
  121. pos+=2;
  122. c-=2;
  123. // write string
  124. CHECK_BIN(len, c);
  125. PUT_BINARY(data, (uint8_t *)StringW, c, pos);
  126. }
  127. else
  128. {
  129. CHECK_SHORT(len);
  130. PUT_SHORT(0); /*pos+=2;*/
  131. }
  132. }
  133. //---------------------------------------------------------------------------
  134. wchar_t *StringField::GetStringW(void)
  135. {
  136. return StringW;
  137. }
  138. //---------------------------------------------------------------------------
  139. void StringField::SetStringW(const wchar_t *Str)
  140. {
  141. if (!Str) return;
  142. ndestring_release(StringW);
  143. StringW = NULL;
  144. StringW = ndestring_wcsdup(Str);
  145. optimized_the=0;
  146. }
  147. //---------------------------------------------------------------------------
  148. void StringField::SetNDEString(wchar_t *Str)
  149. {
  150. if (!Str) return;
  151. // copy and then release, just in case we're copying into ourselves
  152. wchar_t *oldStr = StringW;
  153. StringW = Str;
  154. ndestring_retain(StringW);
  155. ndestring_release(oldStr);
  156. optimized_the=0;
  157. }
  158. //---------------------------------------------------------------------------
  159. size_t StringField::GetDataSize(void)
  160. {
  161. if (StringW)
  162. {
  163. return wcslen(StringW)*2 +2 /*for BOM*/ + 2 /*for byte length*/;
  164. }
  165. else
  166. {
  167. return 2;
  168. }
  169. }
  170. //---------------------------------------------------------------------------
  171. int StringField::Compare(Field *Entry)
  172. {
  173. if (!Entry) return -1;
  174. if (Entry->GetType() != GetType()) return 0;
  175. return mywcsicmp(GetStringW(), ((StringField*)Entry)->GetStringW());
  176. }
  177. //---------------------------------------------------------------------------
  178. int StringField::Starts(Field *Entry)
  179. {
  180. if (!Entry) return -1;
  181. if (Entry->GetType() != GetType()) return 0;
  182. const wchar_t *p = ((StringField*)Entry)->GetStringW();
  183. const wchar_t *d = GetStringW();
  184. if (!d || !p) return 0;
  185. return nde_wcsbegins(d, p);
  186. }
  187. //---------------------------------------------------------------------------
  188. int StringField::Contains(Field *Entry)
  189. {
  190. if (!Entry) return -1;
  191. if (Entry->GetType() != GetType()) return 0;
  192. const wchar_t *p = ((StringField*)Entry)->GetStringW();
  193. const wchar_t *d = GetStringW();
  194. if (!d || !p) return 0;
  195. return nde_wcscontains(GetStringW(), ((StringField*)Entry)->GetStringW());
  196. }
  197. Field *StringField::Clone(Table *pTable)
  198. {
  199. StringField *clone = new StringField(StringW, STRING_IS_NDESTRING);
  200. clone->Pos = FIELD_CLONE;
  201. clone->ID = ID;
  202. clone->MaxSizeOnDisk = (uint32_t)GetDataSize();
  203. return clone;
  204. }
  205. // todo: make configurable words to skip, as well as trailing whitespace removal
  206. #define IsCharSpaceW(c) (c == L' ' || c == L'\t')
  207. 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; }
  208. #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; }
  209. bool StringField::ApplyFilter(Field *Data, int op)
  210. {
  211. // TODO: maybe do this?
  212. if (op == FILTER_ISEMPTY || op == FILTER_ISNOTEMPTY)
  213. {
  214. bool r = (op == FILTER_ISEMPTY);
  215. if (!StringW)
  216. return r;
  217. if (StringW && StringW[0] == 0)
  218. return r;
  219. return !r;
  220. }
  221. //
  222. bool r;
  223. StringField *compField = (StringField *)Data;
  224. const wchar_t *p = compField->GetStringW();
  225. const wchar_t *d = GetStringW();
  226. if (!p)
  227. p = L"";
  228. if (!d)
  229. d = L"";
  230. switch (op)
  231. {
  232. case FILTER_EQUALS:
  233. r = !nde_wcsicmp(d, p);
  234. break;
  235. case FILTER_NOTEQUALS:
  236. r = !!nde_wcsicmp(d, p);
  237. break;
  238. case FILTER_CONTAINS:
  239. r = nde_wcscontains(d, p);
  240. break;
  241. case FILTER_NOTCONTAINS:
  242. r = !nde_wcscontains(d, p);
  243. break;
  244. case FILTER_ABOVE:
  245. r = (bool)(nde_wcsicmp(d, p) > 0);
  246. break;
  247. case FILTER_ABOVEOREQUAL:
  248. r = (bool)(nde_wcsicmp(d, p) >= 0);
  249. break;
  250. case FILTER_BELOW:
  251. r = (bool)(nde_wcsicmp(d, p) < 0);
  252. break;
  253. case FILTER_BELOWOREQUAL:
  254. r = (bool)(nde_wcsicmp(d, p) <= 0);
  255. break;
  256. case FILTER_BEGINS:
  257. r = nde_wcsbegins(d, p);
  258. break;
  259. case FILTER_ENDS:
  260. r = nde_wcsends(d, p);
  261. break;
  262. case FILTER_LIKE:
  263. if (compField->optimized_the)
  264. p = compField->optimized_the;
  265. else
  266. {
  267. SKIP_THE_AND_WHITESPACEW(p);
  268. compField->optimized_the = p;
  269. }
  270. if (optimized_the)
  271. d = optimized_the;
  272. else
  273. {
  274. SKIP_THE_AND_WHITESPACEW(d);
  275. optimized_the=d;
  276. }
  277. r = (bool)(nde_wcsicmp(d, p) == 0);
  278. break;
  279. case FILTER_BEGINSLIKE:
  280. if (compField->optimized_the)
  281. p = compField->optimized_the;
  282. else
  283. {
  284. SKIP_THE_AND_WHITESPACEW(p);
  285. compField->optimized_the = p;
  286. }
  287. if (optimized_the)
  288. d = optimized_the;
  289. else
  290. {
  291. SKIP_THE_AND_WHITESPACEW(d);
  292. optimized_the=d;
  293. }
  294. r = nde_wcsbegins(d, p);
  295. break;
  296. default:
  297. r = true;
  298. break;
  299. }
  300. return r;
  301. }