Atlas - SDL_dialog_utils.c
Home / ext / SDL / src / dialog Lines: 1 | Size: 8034 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "SDL_internal.h" 22 23#include "SDL_dialog_utils.h" 24 25char *convert_filters(const SDL_DialogFileFilter *filters, int nfilters, 26 NameTransform ntf, const char *prefix, 27 const char *separator, const char *suffix, 28 const char *filt_prefix, const char *filt_separator, 29 const char *filt_suffix, const char *ext_prefix, 30 const char *ext_separator, const char *ext_suffix, 31 bool anycase) 32{ 33 char *combined; 34 char *new_combined; 35 char *converted; 36 const char *terminator; 37 size_t new_length; 38 int i; 39 40 if (!filters) { 41 SDL_SetError("Called convert_filters() with NULL filters (SDL bug)"); 42 return NULL; 43 } 44 45 combined = SDL_strdup(prefix); 46 47 if (!combined) { 48 return NULL; 49 } 50 51 for (i = 0; i < nfilters; i++) { 52 const SDL_DialogFileFilter *f = &filters[i]; 53 54 converted = convert_filter(*f, ntf, filt_prefix, filt_separator, 55 filt_suffix, ext_prefix, ext_separator, 56 ext_suffix, anycase); 57 58 if (!converted) { 59 SDL_free(combined); 60 return NULL; 61 } 62 63 terminator = ((i + 1) < nfilters) ? separator : suffix; 64 new_length = SDL_strlen(combined) + SDL_strlen(converted) 65 + SDL_strlen(terminator) + 1; 66 67 new_combined = (char *)SDL_realloc(combined, new_length); 68 69 if (!new_combined) { 70 SDL_free(converted); 71 SDL_free(combined); 72 return NULL; 73 } 74 75 combined = new_combined; 76 77 SDL_strlcat(combined, converted, new_length); 78 SDL_strlcat(combined, terminator, new_length); 79 SDL_free(converted); 80 } 81 82 new_length = SDL_strlen(combined) + SDL_strlen(suffix) + 1; 83 84 new_combined = (char *)SDL_realloc(combined, new_length); 85 86 if (!new_combined) { 87 SDL_free(combined); 88 return NULL; 89 } 90 91 combined = new_combined; 92 93 SDL_strlcat(combined, suffix, new_length); 94 95 return combined; 96} 97 98char *convert_filter(SDL_DialogFileFilter filter, NameTransform ntf, 99 const char *prefix, const char *separator, 100 const char *suffix, const char *ext_prefix, 101 const char *ext_separator, const char *ext_suffix, 102 bool anycase) 103{ 104 char *converted; 105 char *name_filtered; 106 size_t total_length; 107 char *list; 108 109 list = convert_ext_list(filter.pattern, ext_prefix, ext_separator, 110 ext_suffix, anycase); 111 112 if (!list) { 113 return NULL; 114 } 115 116 if (ntf) { 117 name_filtered = ntf(filter.name); 118 } else { 119 // Useless strdup, but easier to read and maintain code this way 120 name_filtered = SDL_strdup(filter.name); 121 } 122 123 if (!name_filtered) { 124 SDL_free(list); 125 return NULL; 126 } 127 128 total_length = SDL_strlen(prefix) + SDL_strlen(name_filtered) 129 + SDL_strlen(separator) + SDL_strlen(list) 130 + SDL_strlen(suffix) + 1; 131 132 converted = (char *) SDL_malloc(total_length); 133 134 if (!converted) { 135 SDL_free(list); 136 SDL_free(name_filtered); 137 return NULL; 138 } 139 140 SDL_snprintf(converted, total_length, "%s%s%s%s%s", prefix, name_filtered, 141 separator, list, suffix); 142 143 SDL_free(list); 144 SDL_free(name_filtered); 145 146 return converted; 147} 148 149char *convert_ext_list(const char *list, const char *prefix, 150 const char *separator, const char *suffix, bool anycase) 151{ 152 char *converted; 153 int semicolons; 154 size_t total_length; 155 156 semicolons = 0; 157 158 for (const char *c = list; *c; c++) { 159 semicolons += (*c == ';'); 160 } 161 162 total_length = 163 (SDL_strlen(list) - semicolons) * 4 // length of list contents (including "a" -> "[aA]") 164 + semicolons * SDL_strlen(separator) // length of separators 165 + SDL_strlen(prefix) + SDL_strlen(suffix) // length of prefix/suffix 166 + 1; // terminating null byte 167 168 converted = (char *) SDL_malloc(total_length); 169 170 if (!converted) { 171 return NULL; 172 } 173 174 *converted = '\0'; 175 176 SDL_strlcat(converted, prefix, total_length); 177 178 /* Some platforms may prefer to handle the asterisk manually, but this 179 function offers to handle it for ease of use. */ 180 if (SDL_strcmp(list, "*") == 0) { 181 SDL_strlcat(converted, "*", total_length); 182 } else { 183 for (const char *c = list; *c; c++) { 184 if (anycase && ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z'))) { 185 char str[5]; 186 str[0] = '['; 187 str[1] = *c; 188 str[2] = *c ^ 0x20; // ASCII case toggle 189 str[3] = ']'; 190 str[4] = '\0'; 191 SDL_strlcat(converted, str, total_length); 192 } else if ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') 193 || (*c >= '0' && *c <= '9') || *c == '-' || *c == '_' 194 || *c == '.') { 195 char str[2]; 196 str[0] = *c; 197 str[1] = '\0'; 198 SDL_strlcat(converted, str, total_length); 199 } else if (*c == ';') { 200 if (c == list || c[-1] == ';') { 201 SDL_SetError("Empty pattern not allowed"); 202 SDL_free(converted); 203 return NULL; 204 } 205 206 SDL_strlcat(converted, separator, total_length); 207 } else { 208 SDL_SetError("Invalid character '%c' in pattern (Only [a-zA-Z0-9_.-] allowed, or a single *)", *c); 209 SDL_free(converted); 210 return NULL; 211 } 212 } 213 } 214 215 if (list[SDL_strlen(list) - 1] == ';') { 216 SDL_SetError("Empty pattern not allowed"); 217 SDL_free(converted); 218 return NULL; 219 } 220 221 SDL_strlcat(converted, suffix, total_length); 222 223 return converted; 224} 225 226const char *validate_filters(const SDL_DialogFileFilter *filters, int nfilters) 227{ 228 if (filters) { 229 for (int i = 0; i < nfilters; i++) { 230 const char *msg = validate_list(filters[i].pattern); 231 232 if (msg) { 233 return msg; 234 } 235 } 236 } 237 238 return NULL; 239} 240 241const char *validate_list(const char *list) 242{ 243 if (SDL_strcmp(list, "*") == 0) { 244 return NULL; 245 } else { 246 for (const char *c = list; *c; c++) { 247 if ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') 248 || (*c >= '0' && *c <= '9') || *c == '-' || *c == '_' 249 || *c == '.') { 250 continue; 251 } else if (*c == ';') { 252 if (c == list || c[-1] == ';') { 253 return "Empty pattern not allowed"; 254 } 255 } else { 256 return "Invalid character in pattern (Only [a-zA-Z0-9_.-] allowed, or a single *)"; 257 } 258 } 259 } 260 261 if (list[SDL_strlen(list) - 1] == ';') { 262 return "Empty pattern not allowed"; 263 } 264 265 return NULL; 266} 267[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.