diff options
author | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
---|---|---|
committer | Jef <jef@targetspot.com> | 2024-09-24 08:54:57 -0400 |
commit | 20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch) | |
tree | 12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Winamp/strutil.cpp | |
parent | 537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff) | |
download | winamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz |
Initial community commit
Diffstat (limited to 'Src/Winamp/strutil.cpp')
-rw-r--r-- | Src/Winamp/strutil.cpp | 486 |
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 |