git subrepo pull --force deps/lightrec
[pcsx_rearmed.git] / deps / libretro-common / playlists / label_sanitization.c
1 /* Copyright  (C) 2010-2020 The RetroArch team
2  *
3  * ---------------------------------------------------------------------------------------
4  * The following license statement only applies to this file (label_sanitization.c).
5  * ---------------------------------------------------------------------------------------
6  *
7  * Permission is hereby granted, free of charge,
8  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22
23 #include <playlists/label_sanitization.h>
24 #include <compat/strl.h>
25 #include <retro_miscellaneous.h>
26 #include <string/stdstring.h>
27 #include <string.h>
28
29 #define DISC_STRINGS_LENGTH   3
30 #define REGION_STRINGS_LENGTH 20
31
32 const char *disc_strings[DISC_STRINGS_LENGTH] = {
33    "(CD",
34    "(Disc",
35    "(Disk"
36 };
37
38 /*
39  * We'll use the standard No-Intro regions for now.
40  */
41 const char *region_strings[REGION_STRINGS_LENGTH] = {
42    "(Australia)", /* Don’t use with Europe */
43    "(Brazil)",
44    "(Canada)",    /* Don’t use with USA */
45    "(China)",
46    "(France)",
47    "(Germany)",
48    "(Hong Kong)",
49    "(Italy)",
50    "(Japan)",
51    "(Korea)",
52    "(Netherlands)",
53    "(Spain)",
54    "(Sweden)",
55    "(USA)",       /* Includes Canada */
56    "(World)",
57    "(Europe)",    /* Includes Australia */
58    "(Asia)",
59    "(Japan, USA)",
60    "(Japan, Europe)",
61    "(USA, Europe)"
62 };
63
64 /**
65  * label_sanitize:
66  *
67  * NOTE: Does not work with nested blocks.
68  **/
69 void label_sanitize(char *label, bool (*left)(char*), bool (*right)(char*))
70 {
71    bool copy = true;
72    int rindex = 0;
73    int lindex = 0;
74    char new_label[PATH_MAX_LENGTH];
75
76    for (; lindex < PATH_MAX_LENGTH && label[lindex] != '\0'; lindex++)
77    {
78       if (copy)
79       {
80          /* check for the start of the range */
81          if ((*left)(&label[lindex]))
82             copy                = false;
83          else
84          {
85             const bool whitespace = label[lindex] == ' ' && (rindex == 0 || new_label[rindex - 1] == ' ');
86
87             /* Simplify consecutive whitespaces */
88             if (!whitespace)
89                new_label[rindex++] = label[lindex];
90          }
91       }
92       else if ((*right)(&label[lindex]))
93          copy = true;
94    }
95
96    /* Trim trailing whitespace */
97    if (rindex > 0 && new_label[rindex - 1] == ' ')
98       new_label[rindex - 1] = '\0';
99    else
100       new_label[rindex] = '\0';
101
102    strlcpy(label, new_label, PATH_MAX_LENGTH);
103 }
104
105 static bool left_parens(char *left)
106 {
107    return left[0] == '(';
108 }
109
110 static bool right_parens(char *right)
111 {
112    return right[0] == ')';
113 }
114
115 static bool left_brackets(char *left)
116 {
117    return left[0] == '[';
118 }
119
120 static bool right_brackets(char *right)
121 {
122    return right[0] == ']';
123 }
124
125 static bool left_parens_or_brackets(char *left)
126 {
127    return left[0] == '(' || left[0] == '[';
128 }
129
130 static bool right_parens_or_brackets(char *right)
131 {
132    return right[0] == ')' || right[0] == ']';
133 }
134
135 static bool left_exclusion(char *left,
136       const char **strings, const size_t strings_count)
137 {
138    unsigned i;
139    char exclusion_string[32];
140    char comparison_string[32];
141
142    strlcpy(exclusion_string, left, sizeof(exclusion_string));
143    string_to_upper(exclusion_string);
144
145    for (i = 0; i < (unsigned)strings_count; i++)
146    {
147       strlcpy(comparison_string, strings[i], sizeof(comparison_string));
148       string_to_upper(comparison_string);
149
150       if (string_starts_with(exclusion_string,
151                comparison_string))
152          return true;
153    }
154
155    return false;
156 }
157
158 static bool left_parens_or_brackets_excluding_region(char *left)
159 {
160    return left_parens_or_brackets(left)
161       && !left_exclusion(left, region_strings, REGION_STRINGS_LENGTH);
162 }
163
164 static bool left_parens_or_brackets_excluding_disc(char *left)
165 {
166    return left_parens_or_brackets(left)
167       && !left_exclusion(left, disc_strings, DISC_STRINGS_LENGTH);
168 }
169
170 static bool left_parens_or_brackets_excluding_region_or_disc(char *left)
171 {
172    return left_parens_or_brackets(left)
173       && !left_exclusion(left, region_strings, REGION_STRINGS_LENGTH)
174       && !left_exclusion(left, disc_strings, DISC_STRINGS_LENGTH);
175 }
176
177 void label_remove_parens(char *label)
178 {
179    label_sanitize(label, left_parens, right_parens);
180 }
181
182 void label_remove_brackets(char *label)
183 {
184    label_sanitize(label, left_brackets, right_brackets);
185 }
186
187 void label_remove_parens_and_brackets(char *label)
188 {
189    label_sanitize(label, left_parens_or_brackets,
190          right_parens_or_brackets);
191 }
192
193 void label_keep_region(char *label)
194 {
195    label_sanitize(label, left_parens_or_brackets_excluding_region,
196          right_parens_or_brackets);
197 }
198
199 void label_keep_disc(char *label)
200 {
201    label_sanitize(label, left_parens_or_brackets_excluding_disc,
202          right_parens_or_brackets);
203 }
204
205 void label_keep_region_and_disc(char *label)
206 {
207    label_sanitize(label, left_parens_or_brackets_excluding_region_or_disc,
208          right_parens_or_brackets);
209 }