strutil.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486
  1. /** (c) Nullsoft, Inc. C O N F I D E N T I A L
  2. ** Filename:
  3. ** Project:
  4. ** Description:
  5. ** Author: Ben Allison [email protected]
  6. ** Created:
  7. **/
  8. #include <windows.h>
  9. #include <Shlwapi.h>
  10. #include "strutil.h"
  11. char *SkipX(char *str, int count)
  12. {
  13. while (count--)
  14. {
  15. str = CharNextA(str);
  16. }
  17. return str;
  18. }
  19. wchar_t *SkipXW(wchar_t *str, int count)
  20. {
  21. while (count--)
  22. {
  23. str = CharNextW(str);
  24. }
  25. return str;
  26. }
  27. void CopyChar(char *dest, const char *src)
  28. {
  29. char *end = CharNextA(src);
  30. ptrdiff_t count = end-src;
  31. while (count--)
  32. {
  33. *dest++=*src++;
  34. }
  35. }
  36. ptrdiff_t CopyCharW(wchar_t *dest, const wchar_t *src)
  37. {
  38. wchar_t *end = CharNextW(src);
  39. ptrdiff_t count = end-src;
  40. for (ptrdiff_t i=0;i<count;i++)
  41. {
  42. *dest++=*src++;
  43. }
  44. return count;
  45. }
  46. void MakeRelativePathName(const wchar_t *filename, wchar_t *outFile, const wchar_t *path)
  47. {
  48. wchar_t outPath[MAX_PATH] = {0};
  49. int common = PathCommonPrefixW(path, filename, outPath);
  50. if (common && common == lstrlenW(path))
  51. {
  52. PathAddBackslashW(outPath);
  53. const wchar_t *p = filename + lstrlenW(outPath);
  54. lstrcpynW(outFile, p, FILENAME_SIZE);
  55. }
  56. else if (!PathIsUNCW(filename) && PathIsSameRootW(filename, path))
  57. {
  58. lstrcpynW(outFile, filename+2, FILENAME_SIZE);
  59. }
  60. }
  61. static int CharacterCompareW(const wchar_t *ch1, const wchar_t *ch2)
  62. {
  63. wchar_t str1[3]={0,0,0}, str2[3]={0,0,0};
  64. CopyCharW(str1, ch1);
  65. CharUpperW(str1);
  66. CopyCharW(str2, ch2);
  67. CharUpperW(str2);
  68. return memcmp(str1, str2, 3*sizeof(wchar_t));
  69. }
  70. static void IncHelperW(LPCWSTR *src, ptrdiff_t *size)
  71. {
  72. wchar_t *end = CharNextW(*src);
  73. ptrdiff_t count = end-*src;
  74. *size-=count;
  75. *src=end;
  76. }
  77. int IsCharDigit(char digit)
  78. {
  79. WORD type=0;
  80. GetStringTypeExA(LOCALE_USER_DEFAULT, CT_CTYPE1, &digit, 1, &type);
  81. return type&C1_DIGIT;
  82. }
  83. int IsCharDigitW(wchar_t digit)
  84. {
  85. WORD type=0;
  86. GetStringTypeExW(LOCALE_USER_DEFAULT, CT_CTYPE1, &digit, 1, &type);
  87. return type&C1_DIGIT;
  88. }
  89. int FileCompareLogical(const wchar_t *str1, const wchar_t *str2)
  90. {
  91. if (str1 && str2)
  92. {
  93. while (str1 && *str1)
  94. {
  95. if (!*str2)
  96. return 1;
  97. else if (IsCharDigitW(*str1))
  98. {
  99. int iStr, iComp;
  100. if (!IsCharDigitW(*str2))
  101. return -1;
  102. /* Compare the numbers */
  103. StrToIntExW(str1, 0, &iStr);
  104. StrToIntExW(str2, 0, &iComp);
  105. if (iStr < iComp)
  106. return -1;
  107. else if (iStr > iComp)
  108. return 1;
  109. /* Skip */
  110. while (IsCharDigitW(*str1))
  111. str1=CharNextW(str1);
  112. while (IsCharDigitW(*str2))
  113. str2=CharNextW(str2);
  114. }
  115. else if (IsCharDigitW(*str2))
  116. return 1;
  117. else
  118. {
  119. int diff = CharacterCompareW(str1, str2);
  120. if (diff > 0)
  121. return 1;
  122. else if (diff < 0)
  123. return -1;
  124. str1=CharNextW(str1);
  125. str2=CharNextW(str2);
  126. }
  127. }
  128. if (*str2)
  129. return -1;
  130. }
  131. return 0;
  132. }
  133. static int StringLengthNoDigits(LPCWSTR str, LPCWSTR *end)
  134. {
  135. ptrdiff_t length=0;
  136. while (str && *str && !IsCharDigitW(*str))
  137. {
  138. IncHelperW(&str, &length);
  139. }
  140. if (end) *end = str;
  141. return (int)(-length); // IncHelper decrements so we need to negate
  142. }
  143. int CompareStringLogical(LPCWSTR str1, LPCWSTR str2)
  144. {
  145. if (str1 && str2)
  146. {
  147. while (str1 && *str1)
  148. {
  149. if (!*str2)
  150. return 1;
  151. else if (IsCharDigitW(*str1))
  152. {
  153. int iStr, iComp;
  154. if (!IsCharDigitW(*str2))
  155. return -1;
  156. /* Compare the numbers */
  157. StrToIntExW(str1, 0, &iStr);
  158. StrToIntExW(str2, 0, &iComp);
  159. if (iStr < iComp)
  160. return -1;
  161. else if (iStr > iComp)
  162. return 1;
  163. /* Skip */
  164. while (IsCharDigitW(*str1))
  165. str1=CharNextW(str1);
  166. while (IsCharDigitW(*str2))
  167. str2=CharNextW(str2);
  168. }
  169. else if (IsCharDigitW(*str2))
  170. return 1;
  171. else
  172. {
  173. LPCWSTR next1, next2;
  174. int len1 = StringLengthNoDigits(str1, &next1);
  175. int len2 = StringLengthNoDigits(str2, &next2);
  176. int comp = CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE|NORM_IGNOREWIDTH, str1, len1, str2, len2);
  177. if (comp == CSTR_LESS_THAN)
  178. return -1;
  179. else if (comp == CSTR_GREATER_THAN)
  180. return 1;
  181. str1 = next1;
  182. str2 = next2;
  183. }
  184. }
  185. if (*str2)
  186. return -1;
  187. }
  188. return 0;
  189. }
  190. int FileCompareLogicalN(LPCWSTR str1, ptrdiff_t str1size, LPCWSTR str2, ptrdiff_t str2size)
  191. {
  192. if (str1 && str2)
  193. {
  194. while (str1 && *str1 && str1size)
  195. {
  196. if (!*str2 || !str2size)
  197. return 1;
  198. else if (IsCharDigitW(*str1))
  199. {
  200. int iStr, iComp;
  201. if (!IsCharDigitW(*str2))
  202. return -1;
  203. /* Compare the numbers */
  204. StrToIntExW(str1, 0, &iStr);
  205. StrToIntExW(str2, 0, &iComp);
  206. if (iStr < iComp)
  207. return -1;
  208. else if (iStr > iComp)
  209. return 1;
  210. /* Skip */
  211. while (IsCharDigitW(*str1))
  212. IncHelperW(&str1, &str1size);
  213. while (IsCharDigitW(*str2))
  214. IncHelperW(&str2, &str2size);
  215. }
  216. else if (IsCharDigitW(*str2))
  217. return 1;
  218. else
  219. {
  220. int diff = CharacterCompareW(str1, str2);
  221. if (diff > 0)
  222. return 1;
  223. else if (diff < 0)
  224. return -1;
  225. IncHelperW(&str1, &str1size);
  226. IncHelperW(&str2, &str2size);
  227. }
  228. }
  229. if (!str1size && !str2size)
  230. return 0;
  231. if (*str2 || str2size < str1size)
  232. return -1;
  233. if (*str1 || str1size < str2size)
  234. return 1;
  235. }
  236. return 0;
  237. }
  238. char *GetLastCharacter(char *string)
  239. {
  240. if (!string || !*string)
  241. return string;
  242. return CharPrevA(string, string+lstrlenA(string));
  243. }
  244. wchar_t *GetLastCharacterW(wchar_t *string)
  245. {
  246. if (!string || !*string)
  247. return string;
  248. return CharPrevW(string, string+lstrlenW(string));
  249. }
  250. const char *GetLastCharacterc(const char *string)
  251. {
  252. if (!string || !*string)
  253. return string;
  254. for (;;)
  255. {
  256. const char *next = CharNextA(string);
  257. if (!*next)
  258. return string;
  259. string = next;
  260. }
  261. }
  262. const wchar_t *GetLastCharactercW(const wchar_t *string)
  263. {
  264. if (!string || !*string)
  265. return string;
  266. return CharPrevW(string, string+lstrlenW(string));
  267. }
  268. wchar_t *scanstr_backW(wchar_t *str, wchar_t *toscan, wchar_t *defval)
  269. {
  270. wchar_t *s = GetLastCharacterW(str);
  271. if (!s || !str[0]) return defval;
  272. if (!toscan || !toscan[0]) return defval;
  273. for (;;)
  274. {
  275. wchar_t *t = toscan;
  276. while (t && *t)
  277. {
  278. if (*t == *s) return s;
  279. t = CharNextW(t);
  280. }
  281. t = CharPrevW(str, s);
  282. if (t == s)
  283. return defval;
  284. s = t;
  285. }
  286. }
  287. const wchar_t *scanstr_backcW(const wchar_t *str, const wchar_t *toscan, const wchar_t *defval)
  288. {
  289. const wchar_t *s = GetLastCharactercW(str);
  290. if (!s || !str[0]) return defval;
  291. if (!toscan || !toscan[0]) return defval;
  292. for (;;)
  293. {
  294. const wchar_t *t = toscan;
  295. while (t && *t)
  296. {
  297. if (*t == *s) return s;
  298. t = CharNextW(t);
  299. }
  300. t = CharPrevW(str, s);
  301. if (t == s)
  302. return defval;
  303. s = t;
  304. }
  305. }
  306. char *scanstr_back(char *str, char *toscan, char *defval)
  307. {
  308. char *s = GetLastCharacter(str);
  309. if (!s || !str[0]) return defval;
  310. if (!toscan || !toscan[0]) return defval;
  311. for (;;)
  312. {
  313. char *t = toscan;
  314. while (t && *t)
  315. {
  316. if (*t == *s) return s;
  317. t = CharNextA(t);
  318. }
  319. t = CharPrevA(str, s);
  320. if (t == s)
  321. return defval;
  322. s = t;
  323. }
  324. }
  325. const char *scanstr_backc(const char *str, const char *toscan, const char *defval)
  326. {
  327. const char *s = GetLastCharacterc(str);
  328. if (!s || !str[0]) return defval;
  329. if (!toscan || !toscan[0]) return defval;
  330. for (;;)
  331. {
  332. const char *t = toscan;
  333. while (t && *t)
  334. {
  335. if (*t == *s) return s;
  336. t = CharNextA(t);
  337. }
  338. t = CharPrevA(str, s);
  339. if (t == s)
  340. return defval;
  341. s = t;
  342. }
  343. }
  344. char *extension(const char *fn)
  345. {
  346. // TODO: deal with making sure that URLs don't return .com, etc.
  347. // e.g. http://www.winamp.com should return nothing
  348. char *end = scanstr_back((char*)fn, "./\\", 0);
  349. if (!end)
  350. return (char*)(fn+lstrlenA(fn));
  351. if (*end == '.')
  352. return CharNextA(end);
  353. return (char*)(fn+lstrlenA(fn));
  354. }
  355. wchar_t *extensionW(const wchar_t *fn)
  356. {
  357. // TODO: deal with making sure that URLs don't return .com, etc.
  358. // e.g. http://www.winamp.com should return nothing
  359. wchar_t *end = scanstr_backW((wchar_t*)fn, L"./\\", 0);
  360. if (!end)
  361. return (wchar_t *)(fn+lstrlenW(fn));
  362. if (*end == L'.')
  363. return CharNextW(end);
  364. return (wchar_t*)(fn+lstrlenW(fn));
  365. }
  366. const char *extensionc(const char *fn)
  367. {
  368. return extension(fn);
  369. }
  370. const wchar_t *extensioncW(const wchar_t *fn)
  371. {
  372. return extensionW(fn);
  373. }
  374. void extension_ex(const char *fn, char *buf, int buflen)
  375. {
  376. const char *s = extensionc(fn);
  377. if (!PathIsURLA(fn)
  378. || (!strstr(s, "?") && !strstr(s, "&") && !strstr(s, "=") && *s))
  379. {
  380. lstrcpynA(buf, s, buflen);
  381. return ;
  382. }
  383. // s is not a terribly good extension, let's try again
  384. {
  385. char *copy = _strdup(fn);
  386. s = "";
  387. again:
  388. {
  389. char *p = scanstr_back(copy, "?", copy);
  390. if (p != copy)
  391. {
  392. *p = 0;
  393. s = extension(copy);
  394. if (!*s) goto again;
  395. }
  396. lstrcpynA(buf, s, buflen);
  397. }
  398. free(copy);
  399. }
  400. }
  401. void extension_exW(const wchar_t *fn, wchar_t *buf, int buflen)
  402. {
  403. const wchar_t *s = extensioncW(fn);
  404. if (!PathIsURLW(fn)
  405. || (!wcsstr(s, L"?") && !wcsstr(s, L"&") && !wcsstr(s, L"=") && *s))
  406. {
  407. lstrcpynW(buf, s, buflen);
  408. return ;
  409. }
  410. // s is not a terribly good extension, let's try again
  411. {
  412. wchar_t *copy = _wcsdup(fn);
  413. s = L"";
  414. again:
  415. {
  416. wchar_t *p = scanstr_backW(copy, L"?", copy);
  417. if (p != copy)
  418. {
  419. *p = 0;
  420. s = extensionW(copy);
  421. if (!*s) goto again;
  422. }
  423. lstrcpynW(buf, s, buflen);
  424. }
  425. free(copy);
  426. }
  427. }