Branch data Line data Source code
1 : : /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
2 : : *
3 : : * Copyright (C) 2015-2016 Richard Hughes <richard@hughsie.com>
4 : : *
5 : : * Licensed under the GNU General Public License Version 2
6 : : *
7 : : * This program is free software; you can redistribute it and/or modify
8 : : * it under the terms of the GNU General Public License as published by
9 : : * the Free Software Foundation; either version 2 of the License, or
10 : : * (at your option) any later version.
11 : : *
12 : : * This program is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 : : * GNU General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU General Public License
18 : : * along with this program; if not, write to the Free Software
19 : : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 : : */
21 : :
22 : : #include "config.h"
23 : :
24 : : #include <appstream-glib.h>
25 : : #include <glib/gi18n-lib.h>
26 : : #include <string.h>
27 : :
28 : : #include "gs-content-rating.h"
29 : :
30 : : #if !AS_CHECK_VERSION(0, 7, 18)
31 : : const gchar *
32 : 0 : gs_content_rating_system_to_str (GsContentRatingSystem system)
33 : : {
34 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_INCAA)
35 : 0 : return "INCAA";
36 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_ACB)
37 : 0 : return "ACB";
38 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_DJCTQ)
39 : 0 : return "DJCTQ";
40 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_GSRR)
41 : 0 : return "GSRR";
42 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_PEGI)
43 : 0 : return "PEGI";
44 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_KAVI)
45 : 0 : return "KAVI";
46 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_USK)
47 : 0 : return "USK";
48 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_ESRA)
49 : 0 : return "ESRA";
50 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_CERO)
51 : 0 : return "CERO";
52 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_OFLCNZ)
53 : 0 : return "OFLCNZ";
54 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_RUSSIA)
55 : 0 : return "RUSSIA";
56 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_MDA)
57 : 0 : return "MDA";
58 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_GRAC)
59 : 0 : return "GRAC";
60 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_ESRB)
61 : 0 : return "ESRB";
62 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_IARC)
63 : 0 : return "IARC";
64 : 0 : return NULL;
65 : : }
66 : :
67 : : /* data obtained from https://en.wikipedia.org/wiki/Video_game_rating_system */
68 : : static char *
69 : 0 : get_esrb_string (const gchar *source, const gchar *translate)
70 : : {
71 [ # # ]: 0 : if (g_strcmp0 (source, translate) == 0)
72 : 0 : return g_strdup (source);
73 : : /* TRANSLATORS: This is the formatting of English and localized name
74 : : of the rating e.g. "Adults Only (solo adultos)" */
75 : 0 : return g_strdup_printf (_("%s (%s)"), source, translate);
76 : : }
77 : :
78 : : /* data obtained from https://en.wikipedia.org/wiki/Video_game_rating_system */
79 : : gchar *
80 : 0 : gs_utils_content_rating_age_to_str (GsContentRatingSystem system, guint age)
81 : : {
82 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_INCAA) {
83 [ # # ]: 0 : if (age >= 18)
84 : 0 : return g_strdup ("+18");
85 [ # # ]: 0 : if (age >= 13)
86 : 0 : return g_strdup ("+13");
87 : 0 : return g_strdup ("ATP");
88 : : }
89 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_ACB) {
90 [ # # ]: 0 : if (age >= 18)
91 : 0 : return g_strdup ("R18+");
92 [ # # ]: 0 : if (age >= 15)
93 : 0 : return g_strdup ("MA15+");
94 : 0 : return g_strdup ("PG");
95 : : }
96 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_DJCTQ) {
97 [ # # ]: 0 : if (age >= 18)
98 : 0 : return g_strdup ("18");
99 [ # # ]: 0 : if (age >= 16)
100 : 0 : return g_strdup ("16");
101 [ # # ]: 0 : if (age >= 14)
102 : 0 : return g_strdup ("14");
103 [ # # ]: 0 : if (age >= 12)
104 : 0 : return g_strdup ("12");
105 [ # # ]: 0 : if (age >= 10)
106 : 0 : return g_strdup ("10");
107 : 0 : return g_strdup ("L");
108 : : }
109 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_GSRR) {
110 [ # # ]: 0 : if (age >= 18)
111 : 0 : return g_strdup ("限制");
112 [ # # ]: 0 : if (age >= 15)
113 : 0 : return g_strdup ("輔15");
114 [ # # ]: 0 : if (age >= 12)
115 : 0 : return g_strdup ("輔12");
116 [ # # ]: 0 : if (age >= 6)
117 : 0 : return g_strdup ("保護");
118 : 0 : return g_strdup ("普通");
119 : : }
120 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_PEGI) {
121 [ # # ]: 0 : if (age >= 18)
122 : 0 : return g_strdup ("18");
123 [ # # ]: 0 : if (age >= 16)
124 : 0 : return g_strdup ("16");
125 [ # # ]: 0 : if (age >= 12)
126 : 0 : return g_strdup ("12");
127 [ # # ]: 0 : if (age >= 7)
128 : 0 : return g_strdup ("7");
129 [ # # ]: 0 : if (age >= 3)
130 : 0 : return g_strdup ("3");
131 : 0 : return NULL;
132 : : }
133 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_KAVI) {
134 [ # # ]: 0 : if (age >= 18)
135 : 0 : return g_strdup ("18+");
136 [ # # ]: 0 : if (age >= 16)
137 : 0 : return g_strdup ("16+");
138 [ # # ]: 0 : if (age >= 12)
139 : 0 : return g_strdup ("12+");
140 [ # # ]: 0 : if (age >= 7)
141 : 0 : return g_strdup ("7+");
142 [ # # ]: 0 : if (age >= 3)
143 : 0 : return g_strdup ("3+");
144 : 0 : return NULL;
145 : : }
146 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_USK) {
147 [ # # ]: 0 : if (age >= 18)
148 : 0 : return g_strdup ("18");
149 [ # # ]: 0 : if (age >= 16)
150 : 0 : return g_strdup ("16");
151 [ # # ]: 0 : if (age >= 12)
152 : 0 : return g_strdup ("12");
153 [ # # ]: 0 : if (age >= 6)
154 : 0 : return g_strdup ("6");
155 : 0 : return g_strdup ("0");
156 : : }
157 : : /* Reference: http://www.esra.org.ir/ */
158 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_ESRA) {
159 [ # # ]: 0 : if (age >= 18)
160 : 0 : return g_strdup ("+18");
161 [ # # ]: 0 : if (age >= 15)
162 : 0 : return g_strdup ("+15");
163 [ # # ]: 0 : if (age >= 12)
164 : 0 : return g_strdup ("+12");
165 [ # # ]: 0 : if (age >= 7)
166 : 0 : return g_strdup ("+7");
167 [ # # ]: 0 : if (age >= 3)
168 : 0 : return g_strdup ("+3");
169 : 0 : return NULL;
170 : : }
171 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_CERO) {
172 [ # # ]: 0 : if (age >= 18)
173 : 0 : return g_strdup ("Z");
174 [ # # ]: 0 : if (age >= 17)
175 : 0 : return g_strdup ("D");
176 [ # # ]: 0 : if (age >= 15)
177 : 0 : return g_strdup ("C");
178 [ # # ]: 0 : if (age >= 12)
179 : 0 : return g_strdup ("B");
180 : 0 : return g_strdup ("A");
181 : : }
182 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_OFLCNZ) {
183 [ # # ]: 0 : if (age >= 18)
184 : 0 : return g_strdup ("R18");
185 [ # # ]: 0 : if (age >= 16)
186 : 0 : return g_strdup ("R16");
187 [ # # ]: 0 : if (age >= 15)
188 : 0 : return g_strdup ("R15");
189 [ # # ]: 0 : if (age >= 13)
190 : 0 : return g_strdup ("R13");
191 : 0 : return g_strdup ("G");
192 : : }
193 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_RUSSIA) {
194 [ # # ]: 0 : if (age >= 18)
195 : 0 : return g_strdup ("18+");
196 [ # # ]: 0 : if (age >= 16)
197 : 0 : return g_strdup ("16+");
198 [ # # ]: 0 : if (age >= 12)
199 : 0 : return g_strdup ("12+");
200 [ # # ]: 0 : if (age >= 6)
201 : 0 : return g_strdup ("6+");
202 : 0 : return g_strdup ("0+");
203 : : }
204 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_MDA) {
205 [ # # ]: 0 : if (age >= 18)
206 : 0 : return g_strdup ("M18");
207 [ # # ]: 0 : if (age >= 16)
208 : 0 : return g_strdup ("ADV");
209 : 0 : return get_esrb_string ("General", _("General"));
210 : : }
211 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_GRAC) {
212 [ # # ]: 0 : if (age >= 18)
213 : 0 : return g_strdup ("18");
214 [ # # ]: 0 : if (age >= 15)
215 : 0 : return g_strdup ("15");
216 [ # # ]: 0 : if (age >= 12)
217 : 0 : return g_strdup ("12");
218 : 0 : return get_esrb_string ("ALL", _("ALL"));
219 : : }
220 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_ESRB) {
221 [ # # ]: 0 : if (age >= 18)
222 : 0 : return get_esrb_string ("Adults Only", _("Adults Only"));
223 [ # # ]: 0 : if (age >= 17)
224 : 0 : return get_esrb_string ("Mature", _("Mature"));
225 [ # # ]: 0 : if (age >= 13)
226 : 0 : return get_esrb_string ("Teen", _("Teen"));
227 [ # # ]: 0 : if (age >= 10)
228 : 0 : return get_esrb_string ("Everyone 10+", _("Everyone 10+"));
229 [ # # ]: 0 : if (age >= 6)
230 : 0 : return get_esrb_string ("Everyone", _("Everyone"));
231 : :
232 : 0 : return get_esrb_string ("Early Childhood", _("Early Childhood"));
233 : : }
234 : : /* IARC = everything else */
235 [ # # ]: 0 : if (age >= 18)
236 : 0 : return g_strdup ("18+");
237 [ # # ]: 0 : if (age >= 16)
238 : 0 : return g_strdup ("16+");
239 [ # # ]: 0 : if (age >= 12)
240 : 0 : return g_strdup ("12+");
241 [ # # ]: 0 : if (age >= 7)
242 : 0 : return g_strdup ("7+");
243 [ # # ]: 0 : if (age >= 3)
244 : 0 : return g_strdup ("3+");
245 : 0 : return NULL;
246 : : }
247 : :
248 : : /*
249 : : * parse_locale:
250 : : * @locale: (transfer full): a locale to parse
251 : : * @language_out: (out) (optional) (nullable): return location for the parsed
252 : : * language, or %NULL to ignore
253 : : * @territory_out: (out) (optional) (nullable): return location for the parsed
254 : : * territory, or %NULL to ignore
255 : : * @codeset_out: (out) (optional) (nullable): return location for the parsed
256 : : * codeset, or %NULL to ignore
257 : : * @modifier_out: (out) (optional) (nullable): return location for the parsed
258 : : * modifier, or %NULL to ignore
259 : : *
260 : : * Parse @locale as a locale string of the form
261 : : * `language[_territory][.codeset][@modifier]` — see `man 3 setlocale` for
262 : : * details.
263 : : *
264 : : * On success, %TRUE will be returned, and the components of the locale will be
265 : : * returned in the given addresses, with each component not including any
266 : : * separators. Otherwise, %FALSE will be returned and the components will be set
267 : : * to %NULL.
268 : : *
269 : : * @locale is modified, and any returned non-%NULL pointers will point inside
270 : : * it.
271 : : *
272 : : * Returns: %TRUE on success, %FALSE otherwise
273 : : */
274 : : static gboolean
275 : 0 : parse_locale (gchar *locale /* (transfer full) */,
276 : : const gchar **language_out,
277 : : const gchar **territory_out,
278 : : const gchar **codeset_out,
279 : : const gchar **modifier_out)
280 : : {
281 : : gchar *separator;
282 : 0 : const gchar *language = NULL, *territory = NULL, *codeset = NULL, *modifier = NULL;
283 : :
284 : 0 : separator = strrchr (locale, '@');
285 [ # # ]: 0 : if (separator != NULL) {
286 : 0 : modifier = separator + 1;
287 : 0 : *separator = '\0';
288 : : }
289 : :
290 : 0 : separator = strrchr (locale, '.');
291 [ # # ]: 0 : if (separator != NULL) {
292 : 0 : codeset = separator + 1;
293 : 0 : *separator = '\0';
294 : : }
295 : :
296 : 0 : separator = strrchr (locale, '_');
297 [ # # ]: 0 : if (separator != NULL) {
298 : 0 : territory = separator + 1;
299 : 0 : *separator = '\0';
300 : : }
301 : :
302 : 0 : language = locale;
303 : :
304 : : /* Parse failure? */
305 [ # # ]: 0 : if (*language == '\0') {
306 : 0 : language = NULL;
307 : 0 : territory = NULL;
308 : 0 : codeset = NULL;
309 : 0 : modifier = NULL;
310 : : }
311 : :
312 [ # # ]: 0 : if (language_out != NULL)
313 : 0 : *language_out = language;
314 [ # # ]: 0 : if (territory_out != NULL)
315 : 0 : *territory_out = territory;
316 [ # # ]: 0 : if (codeset_out != NULL)
317 : 0 : *codeset_out = codeset;
318 [ # # ]: 0 : if (modifier_out != NULL)
319 : 0 : *modifier_out = modifier;
320 : :
321 : 0 : return (language != NULL);
322 : : }
323 : :
324 : : /* data obtained from https://en.wikipedia.org/wiki/Video_game_rating_system */
325 : : GsContentRatingSystem
326 : 0 : gs_utils_content_rating_system_from_locale (const gchar *locale)
327 : : {
328 : 0 : g_autofree gchar *locale_copy = g_strdup (locale);
329 : : const gchar *territory;
330 : :
331 : : /* Default to IARC for locales which can’t be parsed. */
332 [ # # ]: 0 : if (!parse_locale (locale_copy, NULL, &territory, NULL, NULL))
333 : 0 : return GS_CONTENT_RATING_SYSTEM_IARC;
334 : :
335 : : /* Argentina */
336 [ # # ]: 0 : if (g_strcmp0 (territory, "AR") == 0)
337 : 0 : return GS_CONTENT_RATING_SYSTEM_INCAA;
338 : :
339 : : /* Australia */
340 [ # # ]: 0 : if (g_strcmp0 (territory, "AU") == 0)
341 : 0 : return GS_CONTENT_RATING_SYSTEM_ACB;
342 : :
343 : : /* Brazil */
344 [ # # ]: 0 : if (g_strcmp0 (territory, "BR") == 0)
345 : 0 : return GS_CONTENT_RATING_SYSTEM_DJCTQ;
346 : :
347 : : /* Taiwan */
348 [ # # ]: 0 : if (g_strcmp0 (territory, "TW") == 0)
349 : 0 : return GS_CONTENT_RATING_SYSTEM_GSRR;
350 : :
351 : : /* Europe (but not Finland or Germany), India, Israel,
352 : : * Pakistan, Quebec, South Africa */
353 [ # # # # ]: 0 : if ((g_strcmp0 (territory, "GB") == 0) ||
354 [ # # ]: 0 : g_strcmp0 (territory, "AL") == 0 ||
355 [ # # ]: 0 : g_strcmp0 (territory, "AD") == 0 ||
356 [ # # ]: 0 : g_strcmp0 (territory, "AM") == 0 ||
357 [ # # ]: 0 : g_strcmp0 (territory, "AT") == 0 ||
358 [ # # ]: 0 : g_strcmp0 (territory, "AZ") == 0 ||
359 [ # # ]: 0 : g_strcmp0 (territory, "BY") == 0 ||
360 [ # # ]: 0 : g_strcmp0 (territory, "BE") == 0 ||
361 [ # # ]: 0 : g_strcmp0 (territory, "BA") == 0 ||
362 [ # # ]: 0 : g_strcmp0 (territory, "BG") == 0 ||
363 [ # # ]: 0 : g_strcmp0 (territory, "HR") == 0 ||
364 [ # # ]: 0 : g_strcmp0 (territory, "CY") == 0 ||
365 [ # # ]: 0 : g_strcmp0 (territory, "CZ") == 0 ||
366 [ # # ]: 0 : g_strcmp0 (territory, "DK") == 0 ||
367 [ # # ]: 0 : g_strcmp0 (territory, "EE") == 0 ||
368 [ # # ]: 0 : g_strcmp0 (territory, "FR") == 0 ||
369 [ # # ]: 0 : g_strcmp0 (territory, "GE") == 0 ||
370 [ # # ]: 0 : g_strcmp0 (territory, "GR") == 0 ||
371 [ # # ]: 0 : g_strcmp0 (territory, "HU") == 0 ||
372 [ # # ]: 0 : g_strcmp0 (territory, "IS") == 0 ||
373 [ # # ]: 0 : g_strcmp0 (territory, "IT") == 0 ||
374 [ # # ]: 0 : g_strcmp0 (territory, "LZ") == 0 ||
375 [ # # ]: 0 : g_strcmp0 (territory, "XK") == 0 ||
376 [ # # ]: 0 : g_strcmp0 (territory, "LV") == 0 ||
377 [ # # ]: 0 : g_strcmp0 (territory, "FL") == 0 ||
378 [ # # ]: 0 : g_strcmp0 (territory, "LU") == 0 ||
379 [ # # ]: 0 : g_strcmp0 (territory, "LT") == 0 ||
380 [ # # ]: 0 : g_strcmp0 (territory, "MK") == 0 ||
381 [ # # ]: 0 : g_strcmp0 (territory, "MT") == 0 ||
382 [ # # ]: 0 : g_strcmp0 (territory, "MD") == 0 ||
383 [ # # ]: 0 : g_strcmp0 (territory, "MC") == 0 ||
384 [ # # ]: 0 : g_strcmp0 (territory, "ME") == 0 ||
385 [ # # ]: 0 : g_strcmp0 (territory, "NL") == 0 ||
386 [ # # ]: 0 : g_strcmp0 (territory, "NO") == 0 ||
387 [ # # ]: 0 : g_strcmp0 (territory, "PL") == 0 ||
388 [ # # ]: 0 : g_strcmp0 (territory, "PT") == 0 ||
389 [ # # ]: 0 : g_strcmp0 (territory, "RO") == 0 ||
390 [ # # ]: 0 : g_strcmp0 (territory, "SM") == 0 ||
391 [ # # ]: 0 : g_strcmp0 (territory, "RS") == 0 ||
392 [ # # ]: 0 : g_strcmp0 (territory, "SK") == 0 ||
393 [ # # ]: 0 : g_strcmp0 (territory, "SI") == 0 ||
394 [ # # ]: 0 : g_strcmp0 (territory, "ES") == 0 ||
395 [ # # ]: 0 : g_strcmp0 (territory, "SE") == 0 ||
396 [ # # ]: 0 : g_strcmp0 (territory, "CH") == 0 ||
397 [ # # ]: 0 : g_strcmp0 (territory, "TR") == 0 ||
398 [ # # ]: 0 : g_strcmp0 (territory, "UA") == 0 ||
399 [ # # ]: 0 : g_strcmp0 (territory, "VA") == 0 ||
400 [ # # ]: 0 : g_strcmp0 (territory, "IN") == 0 ||
401 [ # # ]: 0 : g_strcmp0 (territory, "IL") == 0 ||
402 [ # # ]: 0 : g_strcmp0 (territory, "PK") == 0 ||
403 : 0 : g_strcmp0 (territory, "ZA") == 0)
404 : 0 : return GS_CONTENT_RATING_SYSTEM_PEGI;
405 : :
406 : : /* Finland */
407 [ # # ]: 0 : if (g_strcmp0 (territory, "FI") == 0)
408 : 0 : return GS_CONTENT_RATING_SYSTEM_KAVI;
409 : :
410 : : /* Germany */
411 [ # # ]: 0 : if (g_strcmp0 (territory, "DE") == 0)
412 : 0 : return GS_CONTENT_RATING_SYSTEM_USK;
413 : :
414 : : /* Iran */
415 [ # # ]: 0 : if (g_strcmp0 (territory, "IR") == 0)
416 : 0 : return GS_CONTENT_RATING_SYSTEM_ESRA;
417 : :
418 : : /* Japan */
419 [ # # ]: 0 : if (g_strcmp0 (territory, "JP") == 0)
420 : 0 : return GS_CONTENT_RATING_SYSTEM_CERO;
421 : :
422 : : /* New Zealand */
423 [ # # ]: 0 : if (g_strcmp0 (territory, "NZ") == 0)
424 : 0 : return GS_CONTENT_RATING_SYSTEM_OFLCNZ;
425 : :
426 : : /* Russia: Content rating law */
427 [ # # ]: 0 : if (g_strcmp0 (territory, "RU") == 0)
428 : 0 : return GS_CONTENT_RATING_SYSTEM_RUSSIA;
429 : :
430 : : /* Singapore */
431 [ # # ]: 0 : if (g_strcmp0 (territory, "SQ") == 0)
432 : 0 : return GS_CONTENT_RATING_SYSTEM_MDA;
433 : :
434 : : /* South Korea */
435 [ # # ]: 0 : if (g_strcmp0 (territory, "KR") == 0)
436 : 0 : return GS_CONTENT_RATING_SYSTEM_GRAC;
437 : :
438 : : /* USA, Canada, Mexico */
439 [ # # # # ]: 0 : if ((g_strcmp0 (territory, "US") == 0) ||
440 [ # # ]: 0 : g_strcmp0 (territory, "CA") == 0 ||
441 : 0 : g_strcmp0 (territory, "MX") == 0)
442 : 0 : return GS_CONTENT_RATING_SYSTEM_ESRB;
443 : :
444 : : /* everything else is IARC */
445 : 0 : return GS_CONTENT_RATING_SYSTEM_IARC;
446 : : }
447 : :
448 : : static const gchar *content_rating_strings[GS_CONTENT_RATING_SYSTEM_LAST][7] = {
449 : : { "3+", "7+", "12+", "16+", "18+", NULL }, /* GS_CONTENT_RATING_SYSTEM_UNKNOWN */
450 : : { "ATP", "+13", "+18", NULL }, /* GS_CONTENT_RATING_SYSTEM_INCAA */
451 : : { "PG", "MA15+", "R18+", NULL }, /* GS_CONTENT_RATING_SYSTEM_ACB */
452 : : { "L", "10", "12", "14", "16", "18", NULL }, /* GS_CONTENT_RATING_SYSTEM_DJCTQ */
453 : : { "普通", "保護", "輔12", "輔15", "限制", NULL }, /* GS_CONTENT_RATING_SYSTEM_GSRR */
454 : : { "3", "7", "12", "16", "18", NULL }, /* GS_CONTENT_RATING_SYSTEM_PEGI */
455 : : { "3+", "7+", "12+", "16+", "18+", NULL }, /* GS_CONTENT_RATING_SYSTEM_KAVI */
456 : : { "0", "6", "12", "16", "18", NULL}, /* GS_CONTENT_RATING_SYSTEM_USK */
457 : : { "+3", "+7", "+12", "+15", "+18", NULL }, /* GS_CONTENT_RATING_SYSTEM_ESRA */
458 : : { "A", "B", "C", "D", "Z", NULL }, /* GS_CONTENT_RATING_SYSTEM_CERO */
459 : : { "G", "R13", "R15", "R16", "R18", NULL }, /* GS_CONTENT_RATING_SYSTEM_OFLCNZ */
460 : : { "0+", "6+", "12+", "16+", "18+", NULL }, /* GS_CONTENT_RATING_SYSTEM_RUSSIA */
461 : : { "General", "ADV", "M18", NULL }, /* GS_CONTENT_RATING_SYSTEM_MDA */
462 : : { "ALL", "12", "15", "18", NULL }, /* GS_CONTENT_RATING_SYSTEM_GRAC */
463 : : { "Early Childhood", "Everyone", "Everyone 10+", "Teen", "Mature", "Adults Only", NULL }, /* GS_CONTENT_RATING_SYSTEM_ESRB */
464 : : { "3+", "7+", "12+", "16+", "18+", NULL }, /* GS_CONTENT_RATING_SYSTEM_IARC */
465 : : };
466 : :
467 : : gchar **
468 : 0 : gs_utils_content_rating_get_values (GsContentRatingSystem system)
469 : : {
470 : 0 : g_return_val_if_fail ((int) system < GS_CONTENT_RATING_SYSTEM_LAST, NULL);
471 : :
472 : : /* IARC is the fallback for everything */
473 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_UNKNOWN)
474 : 0 : system = GS_CONTENT_RATING_SYSTEM_IARC;
475 : :
476 : : /* ESRB is special as it requires localised suffixes */
477 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_ESRB) {
478 : 0 : g_auto(GStrv) esrb_ages = g_new0 (gchar *, 7);
479 : :
480 : 0 : esrb_ages[0] = get_esrb_string (content_rating_strings[system][0], _("Early Childhood"));
481 : 0 : esrb_ages[1] = get_esrb_string (content_rating_strings[system][1], _("Everyone"));
482 : 0 : esrb_ages[2] = get_esrb_string (content_rating_strings[system][2], _("Everyone 10+"));
483 : 0 : esrb_ages[3] = get_esrb_string (content_rating_strings[system][3], _("Teen"));
484 : 0 : esrb_ages[4] = get_esrb_string (content_rating_strings[system][4], _("Mature"));
485 : 0 : esrb_ages[5] = get_esrb_string (content_rating_strings[system][5], _("Adults Only"));
486 : 0 : esrb_ages[6] = NULL;
487 : :
488 : 0 : return g_steal_pointer (&esrb_ages);
489 : : }
490 : :
491 : 0 : return g_strdupv ((gchar **) content_rating_strings[system]);
492 : : }
493 : :
494 : : static guint content_rating_ages[GS_CONTENT_RATING_SYSTEM_LAST][7] = {
495 : : { 3, 7, 12, 16, 18 }, /* GS_CONTENT_RATING_SYSTEM_UNKNOWN */
496 : : { 0, 13, 18 }, /* GS_CONTENT_RATING_SYSTEM_INCAA */
497 : : { 0, 15, 18 }, /* GS_CONTENT_RATING_SYSTEM_ACB */
498 : : { 0, 10, 12, 14, 16, 18 }, /* GS_CONTENT_RATING_SYSTEM_DJCTQ */
499 : : { 0, 6, 12, 15, 18 }, /* GS_CONTENT_RATING_SYSTEM_GSRR */
500 : : { 3, 7, 12, 16, 18 }, /* GS_CONTENT_RATING_SYSTEM_PEGI */
501 : : { 3, 7, 12, 16, 18 }, /* GS_CONTENT_RATING_SYSTEM_KAVI */
502 : : { 0, 6, 12, 16, 18 }, /* GS_CONTENT_RATING_SYSTEM_USK */
503 : : { 3, 7, 12, 15, 18 }, /* GS_CONTENT_RATING_SYSTEM_ESRA */
504 : : { 0, 12, 15, 17, 18 }, /* GS_CONTENT_RATING_SYSTEM_CERO */
505 : : { 0, 13, 15, 16, 18 }, /* GS_CONTENT_RATING_SYSTEM_OFLCNZ */
506 : : { 0, 6, 12, 16, 18 }, /* GS_CONTENT_RATING_SYSTEM_RUSSIA */
507 : : { 0, 16, 18 }, /* GS_CONTENT_RATING_SYSTEM_MDA */
508 : : { 0, 12, 15, 18 }, /* GS_CONTENT_RATING_SYSTEM_GRAC */
509 : : { 0, 6, 10, 13, 17, 18 }, /* GS_CONTENT_RATING_SYSTEM_ESRB */
510 : : { 3, 7, 12, 16, 18 }, /* GS_CONTENT_RATING_SYSTEM_IARC */
511 : : };
512 : :
513 : : const guint *
514 : 0 : gs_utils_content_rating_get_ages (GsContentRatingSystem system, gsize *length_out)
515 : : {
516 : 0 : g_return_val_if_fail ((int) system < GS_CONTENT_RATING_SYSTEM_LAST, NULL);
517 : 0 : g_return_val_if_fail (length_out != NULL, NULL);
518 : :
519 : : /* IARC is the fallback for everything */
520 [ # # ]: 0 : if (system == GS_CONTENT_RATING_SYSTEM_UNKNOWN)
521 : 0 : system = GS_CONTENT_RATING_SYSTEM_IARC;
522 : :
523 : 0 : *length_out = g_strv_length ((gchar **) content_rating_strings[system]);
524 : 0 : return content_rating_ages[system];
525 : : }
526 : :
527 : : typedef enum
528 : : {
529 : : OARS_1_0,
530 : : OARS_1_1,
531 : : } OarsVersion;
532 : :
533 : : /* The struct definition below assumes we don’t grow more
534 : : * #AsContentRating values. */
535 : : G_STATIC_ASSERT (AS_CONTENT_RATING_VALUE_LAST == AS_CONTENT_RATING_VALUE_INTENSE + 1);
536 : :
537 : : static const struct {
538 : : const gchar *id;
539 : : OarsVersion oars_version; /* when the key was first added */
540 : : guint csm_age_none; /* for %AS_CONTENT_RATING_VALUE_NONE */
541 : : guint csm_age_mild; /* for %AS_CONTENT_RATING_VALUE_MILD */
542 : : guint csm_age_moderate; /* for %AS_CONTENT_RATING_VALUE_MODERATE */
543 : : guint csm_age_intense; /* for %AS_CONTENT_RATING_VALUE_INTENSE */
544 : : } oars_to_csm_mappings[] = {
545 : : /* Each @id must only appear once. The set of @csm_age_* values for a
546 : : * given @id must be complete and non-decreasing. */
547 : : /* v1.0 */
548 : : { "violence-cartoon", OARS_1_0, 0, 3, 4, 6 },
549 : : { "violence-fantasy", OARS_1_0, 0, 3, 7, 8 },
550 : : { "violence-realistic", OARS_1_0, 0, 4, 9, 14 },
551 : : { "violence-bloodshed", OARS_1_0, 0, 9, 11, 18 },
552 : : { "violence-sexual", OARS_1_0, 0, 18, 18, 18 },
553 : : { "drugs-alcohol", OARS_1_0, 0, 11, 13, 16 },
554 : : { "drugs-narcotics", OARS_1_0, 0, 12, 14, 17 },
555 : : { "drugs-tobacco", OARS_1_0, 0, 10, 13, 13 },
556 : : { "sex-nudity", OARS_1_0, 0, 12, 14, 14 },
557 : : { "sex-themes", OARS_1_0, 0, 13, 14, 15 },
558 : : { "language-profanity", OARS_1_0, 0, 8, 11, 14 },
559 : : { "language-humor", OARS_1_0, 0, 3, 8, 14 },
560 : : { "language-discrimination", OARS_1_0, 0, 9, 10, 11 },
561 : : { "money-advertising", OARS_1_0, 0, 7, 8, 10 },
562 : : { "money-gambling", OARS_1_0, 0, 7, 10, 18 },
563 : : { "money-purchasing", OARS_1_0, 0, 12, 14, 15 },
564 : : { "social-chat", OARS_1_0, 0, 4, 10, 13 },
565 : : { "social-audio", OARS_1_0, 0, 15, 15, 15 },
566 : : { "social-contacts", OARS_1_0, 0, 12, 12, 12 },
567 : : { "social-info", OARS_1_0, 0, 0, 13, 13 },
568 : : { "social-location", OARS_1_0, 0, 13, 13, 13 },
569 : : /* v1.1 additions */
570 : : { "sex-homosexuality", OARS_1_1, 0, 13, 14, 15 },
571 : : { "sex-prostitution", OARS_1_1, 0, 12, 14, 18 },
572 : : { "sex-adultery", OARS_1_1, 0, 8, 10, 18 },
573 : : { "sex-appearance", OARS_1_1, 0, 10, 10, 15 },
574 : : { "violence-worship", OARS_1_1, 0, 13, 15, 18 },
575 : : { "violence-desecration", OARS_1_1, 0, 13, 15, 18 },
576 : : { "violence-slavery", OARS_1_1, 0, 13, 15, 18 },
577 : : };
578 : : #endif /* appstream-glib < 0.7.18 */
579 : :
580 : : #if !AS_CHECK_VERSION(0, 7, 18)
581 : : /**
582 : : * as_content_rating_id_csm_age_to_value:
583 : : * @id: the subsection ID e.g. "violence-cartoon"
584 : : * @age: the age
585 : : *
586 : : * Gets the #MctAppFilterOarsValue for a given age.
587 : : *
588 : : * Returns: the #MctAppFilterOarsValue
589 : : **/
590 : : MctAppFilterOarsValue
591 : 0 : as_content_rating_id_csm_age_to_value (const gchar *id, guint age)
592 : : {
593 : 0 : for (gsize i = 0; G_N_ELEMENTS (oars_to_csm_mappings); i++) {
594 [ # # ]: 0 : if (g_strcmp0 (id, oars_to_csm_mappings[i].id) == 0) {
595 [ # # ]: 0 : if (age >= oars_to_csm_mappings[i].csm_age_intense)
596 : 0 : return MCT_APP_FILTER_OARS_VALUE_INTENSE;
597 [ # # ]: 0 : else if (age >= oars_to_csm_mappings[i].csm_age_moderate)
598 : 0 : return MCT_APP_FILTER_OARS_VALUE_MODERATE;
599 [ # # ]: 0 : else if (age >= oars_to_csm_mappings[i].csm_age_mild)
600 : 0 : return MCT_APP_FILTER_OARS_VALUE_MILD;
601 [ # # ]: 0 : else if (age >= oars_to_csm_mappings[i].csm_age_none)
602 : 0 : return MCT_APP_FILTER_OARS_VALUE_NONE;
603 : : else
604 : 0 : return MCT_APP_FILTER_OARS_VALUE_UNKNOWN;
605 : : }
606 : : }
607 : :
608 : : return MCT_APP_FILTER_OARS_VALUE_UNKNOWN;
609 : : }
610 : : #endif /* appstream-glib < 0.7.18 */
|