|
@@ -0,0 +1,237 @@
|
|
|
+/*
|
|
|
+ Simple DirectMedia Layer
|
|
|
+ Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
|
|
|
+
|
|
|
+ This software is provided 'as-is', without any express or implied
|
|
|
+ warranty. In no event will the authors be held liable for any damages
|
|
|
+ arising from the use of this software.
|
|
|
+
|
|
|
+ Permission is granted to anyone to use this software for any purpose,
|
|
|
+ including commercial applications, and to alter it and redistribute it
|
|
|
+ freely, subject to the following restrictions:
|
|
|
+
|
|
|
+ 1. The origin of this software must not be misrepresented; you must not
|
|
|
+ claim that you wrote the original software. If you use this software
|
|
|
+ in a product, an acknowledgment in the product documentation would be
|
|
|
+ appreciated but is not required.
|
|
|
+ 2. Altered source versions must be plainly marked as such, and must not be
|
|
|
+ misrepresented as being the original software.
|
|
|
+ 3. This notice may not be removed or altered from any source distribution.
|
|
|
+*/
|
|
|
+#include "SDL_internal.h"
|
|
|
+
|
|
|
+#include "SDL_dialog_utils.h"
|
|
|
+
|
|
|
+char *convert_filters(const SDL_DialogFileFilter *filters, NameTransform ntf,
|
|
|
+ const char *prefix, const char *separator,
|
|
|
+ const char *suffix, const char *filt_prefix,
|
|
|
+ const char *filt_separator, const char *filt_suffix,
|
|
|
+ const char *ext_prefix, const char *ext_separator,
|
|
|
+ const char *ext_suffix)
|
|
|
+{
|
|
|
+ char *combined;
|
|
|
+ char *new_combined;
|
|
|
+ char *converted;
|
|
|
+ const char *terminator;
|
|
|
+ int new_length;
|
|
|
+
|
|
|
+ combined = SDL_strdup(prefix);
|
|
|
+
|
|
|
+ if (!combined) {
|
|
|
+ SDL_OutOfMemory();
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (const SDL_DialogFileFilter *f = filters; f->name; f++) {
|
|
|
+ converted = convert_filter(*f, ntf, filt_prefix, filt_separator,
|
|
|
+ filt_suffix, ext_prefix, ext_separator,
|
|
|
+ ext_suffix);
|
|
|
+
|
|
|
+ if (!converted) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ terminator = f[1].name ? separator : suffix;
|
|
|
+ new_length = SDL_strlen(combined) + SDL_strlen(converted)
|
|
|
+ + SDL_strlen(terminator);
|
|
|
+
|
|
|
+ new_combined = SDL_realloc(combined, new_length);
|
|
|
+
|
|
|
+ if (!new_combined) {
|
|
|
+ SDL_free(converted);
|
|
|
+ SDL_free(combined);
|
|
|
+ SDL_OutOfMemory();
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ combined = new_combined;
|
|
|
+
|
|
|
+ SDL_strlcat(combined, converted, new_length);
|
|
|
+ SDL_strlcat(combined, terminator, new_length);
|
|
|
+ }
|
|
|
+
|
|
|
+ return combined;
|
|
|
+}
|
|
|
+
|
|
|
+char *convert_filter(const SDL_DialogFileFilter filter, NameTransform ntf,
|
|
|
+ const char *prefix, const char *separator,
|
|
|
+ const char *suffix, const char *ext_prefix,
|
|
|
+ const char *ext_separator, const char *ext_suffix)
|
|
|
+{
|
|
|
+ char *converted;
|
|
|
+ char *name_filtered;
|
|
|
+ int total_length;
|
|
|
+ char *list;
|
|
|
+
|
|
|
+ list = convert_ext_list(filter.pattern, ext_prefix, ext_separator,
|
|
|
+ ext_suffix);
|
|
|
+
|
|
|
+ if (!list) {
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ntf) {
|
|
|
+ name_filtered = ntf(filter.name);
|
|
|
+ } else {
|
|
|
+ /* Useless strdup, but easier to read and maintain code this way */
|
|
|
+ name_filtered = SDL_strdup(filter.name);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!name_filtered) {
|
|
|
+ SDL_free(list);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ total_length = SDL_strlen(prefix) + SDL_strlen(name_filtered)
|
|
|
+ + SDL_strlen(separator) + SDL_strlen(list)
|
|
|
+ + SDL_strlen(suffix) + 1;
|
|
|
+
|
|
|
+ converted = (char *) SDL_malloc(total_length);
|
|
|
+
|
|
|
+ if (!converted) {
|
|
|
+ SDL_free(list);
|
|
|
+ SDL_free(name_filtered);
|
|
|
+ SDL_OutOfMemory();
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ SDL_snprintf(converted, total_length, "%s%s%s%s%s", prefix, name_filtered,
|
|
|
+ separator, list, suffix);
|
|
|
+
|
|
|
+ SDL_free(list);
|
|
|
+ SDL_free(name_filtered);
|
|
|
+
|
|
|
+ return converted;
|
|
|
+}
|
|
|
+
|
|
|
+char *convert_ext_list(const char *list, const char *prefix,
|
|
|
+ const char *separator, const char *suffix)
|
|
|
+{
|
|
|
+ char *converted;
|
|
|
+ int semicolons;
|
|
|
+ int total_length;
|
|
|
+
|
|
|
+ semicolons = 0;
|
|
|
+
|
|
|
+ for (const char *c = list; *c; c++) {
|
|
|
+ semicolons += (*c == ';');
|
|
|
+ }
|
|
|
+
|
|
|
+ total_length =
|
|
|
+ SDL_strlen(list) - semicolons /* length of list contents */
|
|
|
+ + semicolons * SDL_strlen(separator) /* length of separators */
|
|
|
+ + SDL_strlen(prefix) + SDL_strlen(suffix) /* length of prefix/suffix */
|
|
|
+ + 1; /* terminating null byte */
|
|
|
+
|
|
|
+ converted = (char *) SDL_malloc(total_length);
|
|
|
+
|
|
|
+ if (!converted) {
|
|
|
+ SDL_OutOfMemory();
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ *converted = '\0';
|
|
|
+
|
|
|
+ SDL_strlcat(converted, prefix, total_length);
|
|
|
+
|
|
|
+ /* Some platforms may prefer to handle the asterisk manually, but this
|
|
|
+ function offers to handle it for ease of use. */
|
|
|
+ if (SDL_strcmp(list, "*") == 0) {
|
|
|
+ SDL_strlcat(converted, "*", total_length);
|
|
|
+ } else {
|
|
|
+ for (const char *c = list; *c; c++) {
|
|
|
+ if ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z')
|
|
|
+ || (*c >= '0' && *c <= '9') || *c == '-' || *c == '_'
|
|
|
+ || *c == '.') {
|
|
|
+ char str[2];
|
|
|
+ str[0] = *c;
|
|
|
+ str[1] = '\0';
|
|
|
+ SDL_strlcat(converted, str, total_length);
|
|
|
+ } else if (*c == ';') {
|
|
|
+ if (c == list || c[-1] == ';') {
|
|
|
+ SDL_SetError("Empty pattern not allowed");
|
|
|
+ SDL_free(converted);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ SDL_strlcat(converted, separator, total_length);
|
|
|
+ } else {
|
|
|
+ SDL_SetError("Invalid character '%c' in pattern (Only [a-zA-Z0-9_.-] allowed, or a single *)", *c);
|
|
|
+ SDL_free(converted);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (list[SDL_strlen(list) - 1] == ';') {
|
|
|
+ SDL_SetError("Empty pattern not allowed");
|
|
|
+ SDL_free(converted);
|
|
|
+ return NULL;
|
|
|
+ }
|
|
|
+
|
|
|
+ SDL_strlcat(converted, suffix, total_length);
|
|
|
+
|
|
|
+ return converted;
|
|
|
+}
|
|
|
+
|
|
|
+const char *validate_filters(const SDL_DialogFileFilter *filters)
|
|
|
+{
|
|
|
+ if (filters) {
|
|
|
+ for (const SDL_DialogFileFilter *f = filters; f->name; f++) {
|
|
|
+ const char *msg = validate_list(f->pattern);
|
|
|
+
|
|
|
+ if (msg) {
|
|
|
+ return msg;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|
|
|
+
|
|
|
+const char *validate_list(const char *list)
|
|
|
+{
|
|
|
+ if (SDL_strcmp(list, "*") == 0) {
|
|
|
+ return NULL;
|
|
|
+ } else {
|
|
|
+ for (const char *c = list; *c; c++) {
|
|
|
+ if ((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z')
|
|
|
+ || (*c >= '0' && *c <= '9') || *c == '-' || *c == '_'
|
|
|
+ || *c == '.') {
|
|
|
+ continue;
|
|
|
+ } else if (*c == ';') {
|
|
|
+ if (c == list || c[-1] == ';') {
|
|
|
+ return "Empty pattern not allowed";
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return "Invalid character in pattern (Only [a-zA-Z0-9_.-] allowed, or a single *)";
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (list[SDL_strlen(list) - 1] == ';') {
|
|
|
+ return "Empty pattern not allowed";
|
|
|
+ }
|
|
|
+
|
|
|
+ return NULL;
|
|
|
+}
|