aboutsummaryrefslogtreecommitdiff
path: root/Src/Winamp/strutil.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Winamp/strutil.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/Winamp/strutil.cpp')
-rw-r--r--Src/Winamp/strutil.cpp486
1 files changed, 486 insertions, 0 deletions
diff --git a/Src/Winamp/strutil.cpp b/Src/Winamp/strutil.cpp
new file mode 100644
index 00000000..abd349ac
--- /dev/null
+++ b/Src/Winamp/strutil.cpp
@@ -0,0 +1,486 @@
+/** (c) Nullsoft, Inc. C O N F I D E N T I A L
+ ** Filename:
+ ** Project:
+ ** Description:
+ ** Author: Ben Allison benski@nullsoft.com
+ ** Created:
+ **/
+
+#include <windows.h>
+#include <Shlwapi.h>
+#include "strutil.h"
+
+char *SkipX(char *str, int count)
+{
+ while (count--)
+ {
+ str = CharNextA(str);
+ }
+
+ return str;
+}
+
+wchar_t *SkipXW(wchar_t *str, int count)
+{
+ while (count--)
+ {
+ str = CharNextW(str);
+ }
+
+ return str;
+}
+
+void CopyChar(char *dest, const char *src)
+{
+ char *end = CharNextA(src);
+ ptrdiff_t count = end-src;
+ while (count--)
+ {
+ *dest++=*src++;
+ }
+}
+
+ptrdiff_t CopyCharW(wchar_t *dest, const wchar_t *src)
+{
+ wchar_t *end = CharNextW(src);
+ ptrdiff_t count = end-src;
+ for (ptrdiff_t i=0;i<count;i++)
+ {
+ *dest++=*src++;
+ }
+ return count;
+}
+
+void MakeRelativePathName(const wchar_t *filename, wchar_t *outFile, const wchar_t *path)
+{
+ wchar_t outPath[MAX_PATH] = {0};
+
+ int common = PathCommonPrefixW(path, filename, outPath);
+ if (common && common == lstrlenW(path))
+ {
+ PathAddBackslashW(outPath);
+ const wchar_t *p = filename + lstrlenW(outPath);
+ lstrcpynW(outFile, p, FILENAME_SIZE);
+ }
+ else if (!PathIsUNCW(filename) && PathIsSameRootW(filename, path))
+ {
+ lstrcpynW(outFile, filename+2, FILENAME_SIZE);
+ }
+}
+
+static int CharacterCompareW(const wchar_t *ch1, const wchar_t *ch2)
+{
+ wchar_t str1[3]={0,0,0}, str2[3]={0,0,0};
+
+ CopyCharW(str1, ch1);
+ CharUpperW(str1);
+
+ CopyCharW(str2, ch2);
+ CharUpperW(str2);
+
+ return memcmp(str1, str2, 3*sizeof(wchar_t));
+}
+
+static void IncHelperW(LPCWSTR *src, ptrdiff_t *size)
+{
+ wchar_t *end = CharNextW(*src);
+ ptrdiff_t count = end-*src;
+ *size-=count;
+ *src=end;
+}
+
+int IsCharDigit(char digit)
+{
+ WORD type=0;
+ GetStringTypeExA(LOCALE_USER_DEFAULT, CT_CTYPE1, &digit, 1, &type);
+ return type&C1_DIGIT;
+}
+
+int IsCharDigitW(wchar_t digit)
+{
+ WORD type=0;
+ GetStringTypeExW(LOCALE_USER_DEFAULT, CT_CTYPE1, &digit, 1, &type);
+ return type&C1_DIGIT;
+}
+
+int FileCompareLogical(const wchar_t *str1, const wchar_t *str2)
+{
+ if (str1 && str2)
+ {
+ while (str1 && *str1)
+ {
+ if (!*str2)
+ return 1;
+ else if (IsCharDigitW(*str1))
+ {
+ int iStr, iComp;
+
+ if (!IsCharDigitW(*str2))
+ return -1;
+
+ /* Compare the numbers */
+ StrToIntExW(str1, 0, &iStr);
+ StrToIntExW(str2, 0, &iComp);
+
+ if (iStr < iComp)
+ return -1;
+ else if (iStr > iComp)
+ return 1;
+
+ /* Skip */
+ while (IsCharDigitW(*str1))
+ str1=CharNextW(str1);
+ while (IsCharDigitW(*str2))
+ str2=CharNextW(str2);
+ }
+ else if (IsCharDigitW(*str2))
+ return 1;
+ else
+ {
+ int diff = CharacterCompareW(str1, str2);
+ if (diff > 0)
+ return 1;
+ else if (diff < 0)
+ return -1;
+
+ str1=CharNextW(str1);
+ str2=CharNextW(str2);
+ }
+ }
+ if (*str2)
+ return -1;
+ }
+ return 0;
+}
+
+static int StringLengthNoDigits(LPCWSTR str, LPCWSTR *end)
+{
+ ptrdiff_t length=0;
+ while (str && *str && !IsCharDigitW(*str))
+ {
+ IncHelperW(&str, &length);
+ }
+ if (end) *end = str;
+ return (int)(-length); // IncHelper decrements so we need to negate
+}
+
+int CompareStringLogical(LPCWSTR str1, LPCWSTR str2)
+{
+ if (str1 && str2)
+ {
+ while (str1 && *str1)
+ {
+ if (!*str2)
+ return 1;
+ else if (IsCharDigitW(*str1))
+ {
+ int iStr, iComp;
+
+ if (!IsCharDigitW(*str2))
+ return -1;
+
+ /* Compare the numbers */
+ StrToIntExW(str1, 0, &iStr);
+ StrToIntExW(str2, 0, &iComp);
+
+ if (iStr < iComp)
+ return -1;
+ else if (iStr > iComp)
+ return 1;
+
+ /* Skip */
+ while (IsCharDigitW(*str1))
+ str1=CharNextW(str1);
+ while (IsCharDigitW(*str2))
+ str2=CharNextW(str2);
+ }
+ else if (IsCharDigitW(*str2))
+ return 1;
+ else
+ {
+ LPCWSTR next1, next2;
+ int len1 = StringLengthNoDigits(str1, &next1);
+ int len2 = StringLengthNoDigits(str2, &next2);
+
+ int comp = CompareStringW(LOCALE_USER_DEFAULT, NORM_IGNORECASE|NORM_IGNOREWIDTH, str1, len1, str2, len2);
+ if (comp == CSTR_LESS_THAN)
+ return -1;
+ else if (comp == CSTR_GREATER_THAN)
+ return 1;
+
+ str1 = next1;
+ str2 = next2;
+ }
+ }
+ if (*str2)
+ return -1;
+ }
+ return 0;
+}
+
+int FileCompareLogicalN(LPCWSTR str1, ptrdiff_t str1size, LPCWSTR str2, ptrdiff_t str2size)
+{
+ if (str1 && str2)
+ {
+ while (str1 && *str1 && str1size)
+ {
+ if (!*str2 || !str2size)
+ return 1;
+ else if (IsCharDigitW(*str1))
+ {
+ int iStr, iComp;
+
+ if (!IsCharDigitW(*str2))
+ return -1;
+
+ /* Compare the numbers */
+ StrToIntExW(str1, 0, &iStr);
+ StrToIntExW(str2, 0, &iComp);
+
+ if (iStr < iComp)
+ return -1;
+ else if (iStr > iComp)
+ return 1;
+
+ /* Skip */
+ while (IsCharDigitW(*str1))
+ IncHelperW(&str1, &str1size);
+ while (IsCharDigitW(*str2))
+ IncHelperW(&str2, &str2size);
+ }
+ else if (IsCharDigitW(*str2))
+ return 1;
+ else
+ {
+ int diff = CharacterCompareW(str1, str2);
+ if (diff > 0)
+ return 1;
+ else if (diff < 0)
+ return -1;
+
+ IncHelperW(&str1, &str1size);
+ IncHelperW(&str2, &str2size);
+ }
+ }
+
+ if (!str1size && !str2size)
+ return 0;
+ if (*str2 || str2size < str1size)
+ return -1;
+ if (*str1 || str1size < str2size)
+ return 1;
+ }
+ return 0;
+}
+
+char *GetLastCharacter(char *string)
+{
+ if (!string || !*string)
+ return string;
+
+ return CharPrevA(string, string+lstrlenA(string));
+}
+
+wchar_t *GetLastCharacterW(wchar_t *string)
+{
+ if (!string || !*string)
+ return string;
+
+ return CharPrevW(string, string+lstrlenW(string));
+}
+
+const char *GetLastCharacterc(const char *string)
+{
+ if (!string || !*string)
+ return string;
+
+ for (;;)
+ {
+ const char *next = CharNextA(string);
+ if (!*next)
+ return string;
+ string = next;
+ }
+}
+
+const wchar_t *GetLastCharactercW(const wchar_t *string)
+{
+ if (!string || !*string)
+ return string;
+
+ return CharPrevW(string, string+lstrlenW(string));
+}
+
+wchar_t *scanstr_backW(wchar_t *str, wchar_t *toscan, wchar_t *defval)
+{
+ wchar_t *s = GetLastCharacterW(str);
+ if (!s || !str[0]) return defval;
+ if (!toscan || !toscan[0]) return defval;
+ for (;;)
+ {
+ wchar_t *t = toscan;
+ while (t && *t)
+ {
+ if (*t == *s) return s;
+ t = CharNextW(t);
+ }
+ t = CharPrevW(str, s);
+ if (t == s)
+ return defval;
+ s = t;
+ }
+}
+
+const wchar_t *scanstr_backcW(const wchar_t *str, const wchar_t *toscan, const wchar_t *defval)
+{
+ const wchar_t *s = GetLastCharactercW(str);
+ if (!s || !str[0]) return defval;
+ if (!toscan || !toscan[0]) return defval;
+ for (;;)
+ {
+ const wchar_t *t = toscan;
+ while (t && *t)
+ {
+ if (*t == *s) return s;
+ t = CharNextW(t);
+ }
+ t = CharPrevW(str, s);
+ if (t == s)
+ return defval;
+ s = t;
+ }
+}
+
+char *scanstr_back(char *str, char *toscan, char *defval)
+{
+ char *s = GetLastCharacter(str);
+ if (!s || !str[0]) return defval;
+ if (!toscan || !toscan[0]) return defval;
+ for (;;)
+ {
+ char *t = toscan;
+ while (t && *t)
+ {
+ if (*t == *s) return s;
+ t = CharNextA(t);
+ }
+ t = CharPrevA(str, s);
+ if (t == s)
+ return defval;
+ s = t;
+ }
+}
+
+const char *scanstr_backc(const char *str, const char *toscan, const char *defval)
+{
+ const char *s = GetLastCharacterc(str);
+ if (!s || !str[0]) return defval;
+ if (!toscan || !toscan[0]) return defval;
+ for (;;)
+ {
+ const char *t = toscan;
+ while (t && *t)
+ {
+ if (*t == *s) return s;
+ t = CharNextA(t);
+ }
+ t = CharPrevA(str, s);
+ if (t == s)
+ return defval;
+ s = t;
+ }
+}
+
+char *extension(const char *fn)
+{
+ // TODO: deal with making sure that URLs don't return .com, etc.
+ // e.g. http://www.winamp.com should return nothing
+ char *end = scanstr_back((char*)fn, "./\\", 0);
+ if (!end)
+ return (char*)(fn+lstrlenA(fn));
+
+ if (*end == '.')
+ return CharNextA(end);
+
+ return (char*)(fn+lstrlenA(fn));
+}
+
+wchar_t *extensionW(const wchar_t *fn)
+{
+ // TODO: deal with making sure that URLs don't return .com, etc.
+ // e.g. http://www.winamp.com should return nothing
+ wchar_t *end = scanstr_backW((wchar_t*)fn, L"./\\", 0);
+ if (!end)
+ return (wchar_t *)(fn+lstrlenW(fn));
+
+ if (*end == L'.')
+ return CharNextW(end);
+
+ return (wchar_t*)(fn+lstrlenW(fn));
+}
+
+const char *extensionc(const char *fn)
+{
+ return extension(fn);
+}
+
+const wchar_t *extensioncW(const wchar_t *fn)
+{
+ return extensionW(fn);
+}
+
+void extension_ex(const char *fn, char *buf, int buflen)
+{
+ const char *s = extensionc(fn);
+ if (!PathIsURLA(fn)
+ || (!strstr(s, "?") && !strstr(s, "&") && !strstr(s, "=") && *s))
+ {
+ lstrcpynA(buf, s, buflen);
+ return ;
+ }
+ // s is not a terribly good extension, let's try again
+ {
+ char *copy = _strdup(fn);
+ s = "";
+ again:
+ {
+ char *p = scanstr_back(copy, "?", copy);
+ if (p != copy)
+ {
+ *p = 0;
+ s = extension(copy);
+ if (!*s) goto again;
+ }
+ lstrcpynA(buf, s, buflen);
+ }
+ free(copy);
+ }
+}
+
+void extension_exW(const wchar_t *fn, wchar_t *buf, int buflen)
+{
+ const wchar_t *s = extensioncW(fn);
+ if (!PathIsURLW(fn)
+ || (!wcsstr(s, L"?") && !wcsstr(s, L"&") && !wcsstr(s, L"=") && *s))
+ {
+ lstrcpynW(buf, s, buflen);
+ return ;
+ }
+ // s is not a terribly good extension, let's try again
+ {
+ wchar_t *copy = _wcsdup(fn);
+ s = L"";
+ again:
+ {
+ wchar_t *p = scanstr_backW(copy, L"?", copy);
+ if (p != copy)
+ {
+ *p = 0;
+ s = extensionW(copy);
+ if (!*s) goto again;
+ }
+ lstrcpynW(buf, s, buflen);
+ }
+ free(copy);
+ }
+} \ No newline at end of file