1 /* Copyright (C) 2010-2019 The RetroArch team
2 *
3 * ---------------------------------------------------------------------------------------
4 * The following license statement only applies to this file (gfx_thumbnail_path.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 <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #include <string/stdstring.h>
28 #include <file/file_path.h>
29 #include <lists/file_list.h>
30
31 #include "../configuration.h"
32 #include "../msg_hash.h"
33 #include "../paths.h"
34 #include "../file_path_special.h"
35
36 #include "gfx_thumbnail_path.h"
37
38 /* Used fixed size char arrays here, just to avoid
39 * the inconvenience of having to calloc()/free()
40 * each individual entry by hand... */
41 struct gfx_thumbnail_path_data
42 {
43 enum playlist_thumbnail_mode playlist_right_mode;
44 enum playlist_thumbnail_mode playlist_left_mode;
45 char system[PATH_MAX_LENGTH];
46 char content_path[PATH_MAX_LENGTH];
47 char content_label[PATH_MAX_LENGTH];
48 char content_core_name[PATH_MAX_LENGTH];
49 char content_db_name[PATH_MAX_LENGTH];
50 char content_img[PATH_MAX_LENGTH];
51 char right_path[PATH_MAX_LENGTH];
52 char left_path[PATH_MAX_LENGTH];
53 };
54
55 /* Resets thumbnail path data
56 * (blanks all internal string containers) */
gfx_thumbnail_path_reset(gfx_thumbnail_path_data_t * path_data)57 void gfx_thumbnail_path_reset(gfx_thumbnail_path_data_t *path_data)
58 {
59 if (!path_data)
60 return;
61
62 path_data->system[0] = '\0';
63 path_data->content_path[0] = '\0';
64 path_data->content_label[0] = '\0';
65 path_data->content_core_name[0] = '\0';
66 path_data->content_db_name[0] = '\0';
67 path_data->content_img[0] = '\0';
68 path_data->right_path[0] = '\0';
69 path_data->left_path[0] = '\0';
70
71 path_data->playlist_right_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT;
72 path_data->playlist_left_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT;
73 }
74
75 /* Initialisation */
76
77 /* Creates new thumbnail path data container.
78 * Returns handle to new gfx_thumbnail_path_data_t object.
79 * on success, otherwise NULL.
80 * Note: Returned object must be free()d */
gfx_thumbnail_path_init(void)81 gfx_thumbnail_path_data_t *gfx_thumbnail_path_init(void)
82 {
83 gfx_thumbnail_path_data_t *path_data = (gfx_thumbnail_path_data_t*)
84 malloc(sizeof(*path_data));
85 if (!path_data)
86 return NULL;
87
88 gfx_thumbnail_path_reset(path_data);
89
90 return path_data;
91 }
92
93
94 /* Utility Functions */
95
96 /* Fetches the thumbnail subdirectory (Named_Snaps,
97 * Named_Titles, Named_Boxarts) corresponding to the
98 * specified 'type index' (1, 2, 3).
99 * Returns true if 'type index' is valid */
gfx_thumbnail_get_sub_directory(unsigned type_idx,const char ** sub_directory)100 bool gfx_thumbnail_get_sub_directory(
101 unsigned type_idx, const char **sub_directory)
102 {
103 if (!sub_directory)
104 return false;
105
106 switch (type_idx)
107 {
108 case 1:
109 *sub_directory = "Named_Snaps";
110 return true;
111 case 2:
112 *sub_directory = "Named_Titles";
113 return true;
114 case 3:
115 *sub_directory = "Named_Boxarts";
116 return true;
117 case 0:
118 default:
119 break;
120 }
121
122 return false;
123 }
124
125 /* Returns currently set thumbnail 'type' (Named_Snaps,
126 * Named_Titles, Named_Boxarts) for specified thumbnail
127 * identifier (right, left) */
gfx_thumbnail_get_type(settings_t * settings,gfx_thumbnail_path_data_t * path_data,enum gfx_thumbnail_id thumbnail_id)128 static const char *gfx_thumbnail_get_type(
129 settings_t *settings,
130 gfx_thumbnail_path_data_t *path_data,
131 enum gfx_thumbnail_id thumbnail_id)
132 {
133 unsigned type = 0;
134 unsigned gfx_thumbnails = settings->uints.gfx_thumbnails;
135 unsigned menu_left_thumbnails = settings->uints.menu_left_thumbnails;
136
137 if (!path_data)
138 return msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF);
139
140 switch (thumbnail_id)
141 {
142 case GFX_THUMBNAIL_RIGHT:
143 if (path_data->playlist_right_mode != PLAYLIST_THUMBNAIL_MODE_DEFAULT)
144 type = (unsigned)path_data->playlist_right_mode - 1;
145 else
146 type = gfx_thumbnails;
147 break;
148 case GFX_THUMBNAIL_LEFT:
149 if (path_data->playlist_left_mode != PLAYLIST_THUMBNAIL_MODE_DEFAULT)
150 type = (unsigned)path_data->playlist_left_mode - 1;
151 else
152 type = menu_left_thumbnails;
153 break;
154 default:
155 return msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF);
156 }
157
158 switch (type)
159 {
160 case 1:
161 return "Named_Snaps";
162 case 2:
163 return "Named_Titles";
164 case 3:
165 return "Named_Boxarts";
166 case 0:
167 default:
168 break;
169 }
170
171 return msg_hash_to_str(MENU_ENUM_LABEL_VALUE_OFF);
172 }
173
174 /* Returns true if specified thumbnail is enabled
175 * (i.e. if 'type' is not equal to MENU_ENUM_LABEL_VALUE_OFF) */
gfx_thumbnail_is_enabled(gfx_thumbnail_path_data_t * path_data,enum gfx_thumbnail_id thumbnail_id)176 bool gfx_thumbnail_is_enabled(gfx_thumbnail_path_data_t *path_data, enum gfx_thumbnail_id thumbnail_id)
177 {
178 settings_t *settings = config_get_ptr();
179 unsigned gfx_thumbnails = settings->uints.gfx_thumbnails;
180 unsigned menu_left_thumbnails = settings->uints.menu_left_thumbnails;
181
182 if (!path_data)
183 return false;
184
185 switch (thumbnail_id)
186 {
187 case GFX_THUMBNAIL_RIGHT:
188 if (path_data->playlist_right_mode != PLAYLIST_THUMBNAIL_MODE_DEFAULT)
189 return path_data->playlist_right_mode != PLAYLIST_THUMBNAIL_MODE_OFF;
190 return gfx_thumbnails != 0;
191 case GFX_THUMBNAIL_LEFT:
192 if (path_data->playlist_left_mode != PLAYLIST_THUMBNAIL_MODE_DEFAULT)
193 return path_data->playlist_left_mode != PLAYLIST_THUMBNAIL_MODE_OFF;
194 return menu_left_thumbnails != 0;
195 default:
196 break;
197 }
198
199 return false;
200 }
201
202 /* Setters */
203
204 /* Fills content_img field of path_data using existing
205 * content_label field (for internal use only) */
fill_content_img(gfx_thumbnail_path_data_t * path_data)206 static void fill_content_img(gfx_thumbnail_path_data_t *path_data)
207 {
208 char *scrub_char_pointer = NULL;
209
210 /* Copy source label string */
211 strlcpy(path_data->content_img,
212 path_data->content_label, sizeof(path_data->content_img));
213
214 /* Scrub characters that are not cross-platform and/or violate the
215 * No-Intro filename standard:
216 * http://datomatic.no-intro.org/stuff/The%20Official%20No-Intro%20Convention%20(20071030).zip
217 * Replace these characters in the entry name with underscores */
218 while ((scrub_char_pointer =
219 strpbrk(path_data->content_img, "&*/:`\"<>?\\|")))
220 *scrub_char_pointer = '_';
221
222 /* Add PNG extension */
223 strlcat(path_data->content_img, ".png", sizeof(path_data->content_img));
224 }
225
226 /* Sets current 'system' (default database name).
227 * Returns true if 'system' is valid.
228 * If playlist is provided, extracts system-specific
229 * thumbnail assignment metadata (required for accurate
230 * usage of gfx_thumbnail_is_enabled())
231 * > Used as a fallback when individual content lacks an
232 * associated database name */
gfx_thumbnail_set_system(gfx_thumbnail_path_data_t * path_data,const char * system,playlist_t * playlist)233 bool gfx_thumbnail_set_system(gfx_thumbnail_path_data_t *path_data,
234 const char *system, playlist_t *playlist)
235 {
236 if (!path_data)
237 return false;
238
239 /* When system is updated, must regenerate right/left
240 * thumbnail paths */
241 path_data->right_path[0] = '\0';
242 path_data->left_path[0] = '\0';
243
244 /* 'Reset' path_data system string */
245 path_data->system[0] = '\0';
246
247 /* Must also reset playlist thumbnail display modes */
248 path_data->playlist_right_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT;
249 path_data->playlist_left_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT;
250
251 if (string_is_empty(system))
252 return false;
253
254 /* Hack: There is only one MAME thumbnail repo,
255 * so filter any input starting with 'MAME...' */
256 if (strncmp(system, "MAME", 4) == 0)
257 strlcpy(path_data->system, "MAME", sizeof(path_data->system));
258 else
259 strlcpy(path_data->system, system, sizeof(path_data->system));
260
261 /* Addendum: Now that we have per-playlist thumbnail display
262 * modes, we must extract them here - otherwise
263 * gfx_thumbnail_is_enabled() will go out of sync */
264 if (playlist)
265 {
266 const char *playlist_path = playlist_get_conf_path(playlist);
267 const char *playlist_file = NULL;
268 bool playlist_valid = false;
269
270 /* Note: This is not considered an error
271 * (just means that input playlist is ignored) */
272 if (string_is_empty(playlist_path))
273 return true;
274
275 playlist_file = path_basename_nocompression(playlist_path);
276
277 /* Note: This is not considered an error
278 * (just means that input playlist is ignored) */
279 if (string_is_empty(playlist_file))
280 return true;
281
282 /* Check for history/favourites playlists */
283 playlist_valid =
284 (string_is_equal(system, "history") &&
285 string_is_equal(playlist_file,
286 FILE_PATH_CONTENT_HISTORY)) ||
287 (string_is_equal(system, "favorites") &&
288 string_is_equal(playlist_file,
289 FILE_PATH_CONTENT_FAVORITES));
290
291 if (!playlist_valid)
292 {
293 /* This means we have to work a little harder
294 * i.e. check whether the cached playlist file
295 * matches the database name */
296 char *playlist_name = NULL;
297 char tmp[PATH_MAX_LENGTH];
298
299 tmp[0] = '\0';
300
301 strlcpy(tmp, playlist_file, sizeof(tmp));
302 playlist_name = path_remove_extension(tmp);
303 playlist_valid = string_is_equal(playlist_name, system);
304 }
305
306 /* If we have a valid playlist, extract thumbnail modes */
307 if (playlist_valid)
308 {
309 path_data->playlist_right_mode =
310 playlist_get_thumbnail_mode(playlist, PLAYLIST_THUMBNAIL_RIGHT);
311 path_data->playlist_left_mode =
312 playlist_get_thumbnail_mode(playlist, PLAYLIST_THUMBNAIL_LEFT);
313 }
314 }
315
316 return true;
317 }
318
319 /* Sets current thumbnail content according to the specified label.
320 * Returns true if content is valid */
gfx_thumbnail_set_content(gfx_thumbnail_path_data_t * path_data,const char * label)321 bool gfx_thumbnail_set_content(gfx_thumbnail_path_data_t *path_data, const char *label)
322 {
323 if (!path_data)
324 return false;
325
326 /* When content is updated, must regenerate right/left
327 * thumbnail paths */
328 path_data->right_path[0] = '\0';
329 path_data->left_path[0] = '\0';
330
331 /* 'Reset' path_data content strings */
332 path_data->content_path[0] = '\0';
333 path_data->content_label[0] = '\0';
334 path_data->content_core_name[0] = '\0';
335 path_data->content_db_name[0] = '\0';
336 path_data->content_img[0] = '\0';
337
338 /* Must also reset playlist thumbnail display modes */
339 path_data->playlist_right_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT;
340 path_data->playlist_left_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT;
341
342 if (string_is_empty(label))
343 return false;
344
345 /* Cache content label */
346 strlcpy(path_data->content_label, label, sizeof(path_data->content_label));
347
348 /* Determine content image name */
349 fill_content_img(path_data);
350
351 /* Have to set content path to *something*...
352 * Just use label value (it doesn't matter) */
353 strlcpy(path_data->content_path, label, sizeof(path_data->content_path));
354
355 /* Redundant error check... */
356 return !string_is_empty(path_data->content_img);
357 }
358
359 /* Sets current thumbnail content to the specified image.
360 * Returns true if content is valid */
gfx_thumbnail_set_content_image(gfx_thumbnail_path_data_t * path_data,const char * img_dir,const char * img_name)361 bool gfx_thumbnail_set_content_image(
362 gfx_thumbnail_path_data_t *path_data,
363 const char *img_dir, const char *img_name)
364 {
365 char *content_img_no_ext = NULL;
366
367 if (!path_data)
368 return false;
369
370 /* When content is updated, must regenerate right/left
371 * thumbnail paths */
372 path_data->right_path[0] = '\0';
373 path_data->left_path[0] = '\0';
374
375 /* 'Reset' path_data content strings */
376 path_data->content_path[0] = '\0';
377 path_data->content_label[0] = '\0';
378 path_data->content_core_name[0] = '\0';
379 path_data->content_db_name[0] = '\0';
380 path_data->content_img[0] = '\0';
381
382 /* Must also reset playlist thumbnail display modes */
383 path_data->playlist_right_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT;
384 path_data->playlist_left_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT;
385
386 if (string_is_empty(img_dir) || string_is_empty(img_name))
387 return false;
388
389 if (path_is_media_type(img_name) != RARCH_CONTENT_IMAGE)
390 return false;
391
392 /* Cache content image name */
393 strlcpy(path_data->content_img,
394 img_name, sizeof(path_data->content_img));
395
396 /* Get image label */
397 content_img_no_ext = path_remove_extension(path_data->content_img);
398 if (!string_is_empty(content_img_no_ext))
399 strlcpy(path_data->content_label,
400 content_img_no_ext, sizeof(path_data->content_label));
401 else
402 strlcpy(path_data->content_label,
403 path_data->content_img, sizeof(path_data->content_label));
404
405 /* Set file path */
406 fill_pathname_join(path_data->content_path,
407 img_dir, img_name, sizeof(path_data->content_path));
408
409 /* Set core name to "imageviewer" */
410 strlcpy(
411 path_data->content_core_name,
412 "imageviewer", sizeof(path_data->content_core_name));
413
414 /* Set database name (arbitrarily) to "_images_"
415 * (required for compatibility with gfx_thumbnail_update_path(),
416 * but not actually used...) */
417 strlcpy(path_data->content_db_name,
418 "_images_", sizeof(path_data->content_db_name));
419
420 /* Redundant error check */
421 return !string_is_empty(path_data->content_path);
422 }
423
424 /* Sets current thumbnail content to the specified playlist entry.
425 * Returns true if content is valid.
426 * > Note: It is always best to use playlists when setting
427 * thumbnail content, since there is no guarantee that the
428 * corresponding menu entry label will contain a useful
429 * identifier (it may be 'tainted', e.g. with the current
430 * core name). 'Real' labels should be extracted from source */
gfx_thumbnail_set_content_playlist(gfx_thumbnail_path_data_t * path_data,playlist_t * playlist,size_t idx)431 bool gfx_thumbnail_set_content_playlist(
432 gfx_thumbnail_path_data_t *path_data, playlist_t *playlist, size_t idx)
433 {
434 const char *content_path = NULL;
435 const char *content_label = NULL;
436 const char *core_name = NULL;
437 const char *db_name = NULL;
438 const struct playlist_entry *entry = NULL;
439
440 if (!path_data)
441 return false;
442
443 /* When content is updated, must regenerate right/left
444 * thumbnail paths */
445 path_data->right_path[0] = '\0';
446 path_data->left_path[0] = '\0';
447
448 /* 'Reset' path_data content strings */
449 path_data->content_path[0] = '\0';
450 path_data->content_label[0] = '\0';
451 path_data->content_core_name[0] = '\0';
452 path_data->content_db_name[0] = '\0';
453 path_data->content_img[0] = '\0';
454
455 /* Must also reset playlist thumbnail display modes */
456 path_data->playlist_right_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT;
457 path_data->playlist_left_mode = PLAYLIST_THUMBNAIL_MODE_DEFAULT;
458
459 if (!playlist)
460 return false;
461
462 if (idx >= playlist_get_size(playlist))
463 return false;
464
465 /* Read playlist values */
466 playlist_get_index(playlist, idx, &entry);
467
468 if (!entry)
469 return false;
470
471 content_path = entry->path;
472 content_label = entry->label;
473 core_name = entry->core_name;
474 db_name = entry->db_name;
475
476 /* Content without a path is invalid by definition */
477 if (string_is_empty(content_path))
478 return false;
479
480 /* Cache content path
481 * (This is required for imageviewer, history and favourites content) */
482 strlcpy(path_data->content_path,
483 content_path, sizeof(path_data->content_path));
484
485 /* Cache core name
486 * (This is required for imageviewer content) */
487 if (!string_is_empty(core_name))
488 strlcpy(path_data->content_core_name,
489 core_name, sizeof(path_data->content_core_name));
490
491 /* Get content label */
492 if (!string_is_empty(content_label))
493 strlcpy(path_data->content_label,
494 content_label, sizeof(path_data->content_label));
495 else
496 fill_short_pathname_representation(path_data->content_label,
497 content_path, sizeof(path_data->content_label));
498
499 /* Determine content image name */
500 fill_content_img(path_data);
501
502 /* Redundant error check... */
503 if (string_is_empty(path_data->content_img))
504 return false;
505
506 /* Thumbnail image name is done -> now check if
507 * per-content database name is defined */
508 if (!string_is_empty(db_name))
509 {
510 /* Hack: There is only one MAME thumbnail repo,
511 * so filter any input starting with 'MAME...' */
512 if (strncmp(db_name, "MAME", 4) == 0)
513 strlcpy(path_data->content_db_name, "MAME",
514 sizeof(path_data->content_db_name));
515 else
516 {
517 char *db_name_no_ext = NULL;
518 char tmp_buf[PATH_MAX_LENGTH];
519 tmp_buf[0] = '\0';
520
521 /* Remove .lpl extension
522 * > path_remove_extension() requires a char * (not const)
523 * so have to use a temporary buffer... */
524 strlcpy(tmp_buf, db_name, sizeof(tmp_buf));
525 db_name_no_ext = path_remove_extension(tmp_buf);
526
527 if (!string_is_empty(db_name_no_ext))
528 strlcpy(path_data->content_db_name,
529 db_name_no_ext, sizeof(path_data->content_db_name));
530 else
531 strlcpy(path_data->content_db_name,
532 tmp_buf, sizeof(path_data->content_db_name));
533 }
534 }
535
536 /* Playlist entry is valid -> it is now 'safe' to
537 * extract any remaining playlist metadata
538 * (i.e. thumbnail display modes) */
539 path_data->playlist_right_mode =
540 playlist_get_thumbnail_mode(playlist, PLAYLIST_THUMBNAIL_RIGHT);
541 path_data->playlist_left_mode =
542 playlist_get_thumbnail_mode(playlist, PLAYLIST_THUMBNAIL_LEFT);
543
544 return true;
545 }
546
547 /* Updaters */
548
549 /* Updates path for specified thumbnail identifier (right, left).
550 * Must be called after:
551 * - gfx_thumbnail_set_system()
552 * - gfx_thumbnail_set_content*()
553 * ...and before:
554 * - gfx_thumbnail_get_path()
555 * Returns true if generated path is valid */
gfx_thumbnail_update_path(gfx_thumbnail_path_data_t * path_data,enum gfx_thumbnail_id thumbnail_id)556 bool gfx_thumbnail_update_path(
557 gfx_thumbnail_path_data_t *path_data,
558 enum gfx_thumbnail_id thumbnail_id)
559 {
560 char content_dir[PATH_MAX_LENGTH];
561 settings_t *settings = config_get_ptr();
562 const char *type = gfx_thumbnail_get_type(settings,
563 path_data, thumbnail_id);
564 const char *system_name = NULL;
565 char *thumbnail_path = NULL;
566 const char *dir_thumbnails = settings ? settings->paths.directory_thumbnails : NULL;
567
568 if (!path_data)
569 return false;
570
571 /* Determine which path we are updating... */
572 switch (thumbnail_id)
573 {
574 case GFX_THUMBNAIL_RIGHT:
575 thumbnail_path = path_data->right_path;
576 break;
577 case GFX_THUMBNAIL_LEFT:
578 thumbnail_path = path_data->left_path;
579 break;
580 default:
581 return false;
582 }
583
584 thumbnail_path[0] = '\0';
585 content_dir[0] = '\0';
586
587 /* Sundry error checking */
588 if (string_is_empty(dir_thumbnails))
589 return false;
590
591 if (!gfx_thumbnail_is_enabled(path_data, thumbnail_id))
592 return false;
593
594 /* Generate new path */
595
596 /* > Check path_data for empty strings */
597 if (string_is_empty(path_data->content_path) ||
598 string_is_empty(path_data->content_img) ||
599 (string_is_empty(path_data->system) &&
600 string_is_empty(path_data->content_db_name)))
601 return false;
602
603 /* > Get current system */
604 if (string_is_empty(path_data->content_db_name))
605 {
606 /* If this is a content history or favorites playlist
607 * then the current 'path_data->system' string is
608 * meaningless. In this case, we fall back to the
609 * content directory name */
610 if (string_is_equal(path_data->system, "history") ||
611 string_is_equal(path_data->system, "favorites"))
612 {
613 if (!gfx_thumbnail_get_content_dir(
614 path_data, content_dir, sizeof(content_dir)))
615 return false;
616
617 system_name = content_dir;
618 }
619 else
620 system_name = path_data->system;
621 }
622 else
623 system_name = path_data->content_db_name;
624
625 /* > Special case: thumbnail for imageviewer content
626 * is the image file itself */
627 if (string_is_equal(system_name, "images_history") ||
628 string_is_equal(path_data->content_core_name, "imageviewer"))
629 {
630 /* imageviewer content is identical for left and right thumbnails */
631 if (path_is_media_type(path_data->content_path) == RARCH_CONTENT_IMAGE)
632 strlcpy(thumbnail_path,
633 path_data->content_path, PATH_MAX_LENGTH * sizeof(char));
634 }
635 else
636 {
637 char tmp_buf[PATH_MAX_LENGTH];
638 tmp_buf[0] = '\0';
639
640 /* > Normal content: assemble path */
641
642 /* >> Base + system name */
643 fill_pathname_join(thumbnail_path, dir_thumbnails,
644 system_name, PATH_MAX_LENGTH * sizeof(char));
645
646 /* >> Add type */
647 fill_pathname_join(tmp_buf, thumbnail_path, type, sizeof(tmp_buf));
648
649 /* >> Add content image */
650 thumbnail_path[0] = '\0';
651 fill_pathname_join(thumbnail_path, tmp_buf,
652 path_data->content_img, PATH_MAX_LENGTH * sizeof(char));
653 }
654
655 /* Final error check - is cached path empty? */
656 return !string_is_empty(thumbnail_path);
657 }
658
659 /* Getters */
660
661 /* Fetches the current thumbnail file path of the
662 * specified thumbnail 'type'.
663 * Returns true if path is valid. */
gfx_thumbnail_get_path(gfx_thumbnail_path_data_t * path_data,enum gfx_thumbnail_id thumbnail_id,const char ** path)664 bool gfx_thumbnail_get_path(
665 gfx_thumbnail_path_data_t *path_data,
666 enum gfx_thumbnail_id thumbnail_id, const char **path)
667 {
668 char *thumbnail_path = NULL;
669
670 if (!path_data || !path)
671 return false;
672
673 switch (thumbnail_id)
674 {
675 case GFX_THUMBNAIL_RIGHT:
676 if (!string_is_empty(path_data->right_path))
677 {
678 thumbnail_path = path_data->right_path;
679 *path = thumbnail_path;
680 return true;
681 }
682 break;
683 case GFX_THUMBNAIL_LEFT:
684 if (!string_is_empty(path_data->left_path))
685 {
686 thumbnail_path = path_data->left_path;
687 *path = thumbnail_path;
688 return true;
689 }
690 break;
691 default:
692 break;
693 }
694
695 return false;
696 }
697
698 /* Fetches current 'system' (default database name).
699 * Returns true if 'system' is valid. */
gfx_thumbnail_get_system(gfx_thumbnail_path_data_t * path_data,const char ** system)700 bool gfx_thumbnail_get_system(
701 gfx_thumbnail_path_data_t *path_data, const char **system)
702 {
703 if (!path_data || !system)
704 return false;
705 if (string_is_empty(path_data->system))
706 return false;
707
708 *system = path_data->system;
709
710 return true;
711 }
712
713 /* Fetches current content path.
714 * Returns true if content path is valid. */
gfx_thumbnail_get_content_path(gfx_thumbnail_path_data_t * path_data,const char ** content_path)715 bool gfx_thumbnail_get_content_path(
716 gfx_thumbnail_path_data_t *path_data, const char **content_path)
717 {
718 if (!path_data || !content_path)
719 return false;
720 if (string_is_empty(path_data->content_path))
721 return false;
722
723 *content_path = path_data->content_path;
724
725 return true;
726 }
727
728 /* Fetches current thumbnail label.
729 * Returns true if label is valid. */
gfx_thumbnail_get_label(gfx_thumbnail_path_data_t * path_data,const char ** label)730 bool gfx_thumbnail_get_label(
731 gfx_thumbnail_path_data_t *path_data, const char **label)
732 {
733 if (!path_data || !label)
734 return false;
735 if (string_is_empty(path_data->content_label))
736 return false;
737
738 *label = path_data->content_label;
739
740 return true;
741 }
742
743 /* Fetches current thumbnail core name.
744 * Returns true if core name is valid. */
gfx_thumbnail_get_core_name(gfx_thumbnail_path_data_t * path_data,const char ** core_name)745 bool gfx_thumbnail_get_core_name(
746 gfx_thumbnail_path_data_t *path_data, const char **core_name)
747 {
748 if (!path_data || !core_name)
749 return false;
750 if (string_is_empty(path_data->content_core_name))
751 return false;
752
753 *core_name = path_data->content_core_name;
754
755 return true;
756 }
757
758 /* Fetches current database name.
759 * Returns true if database name is valid. */
gfx_thumbnail_get_db_name(gfx_thumbnail_path_data_t * path_data,const char ** db_name)760 bool gfx_thumbnail_get_db_name(
761 gfx_thumbnail_path_data_t *path_data, const char **db_name)
762 {
763 if (!path_data || !db_name)
764 return false;
765 if (string_is_empty(path_data->content_db_name))
766 return false;
767
768 *db_name = path_data->content_db_name;
769
770 return true;
771 }
772
773 /* Fetches current thumbnail image name
774 * (name is the same for all thumbnail types).
775 * Returns true if image name is valid. */
gfx_thumbnail_get_img_name(gfx_thumbnail_path_data_t * path_data,const char ** img_name)776 bool gfx_thumbnail_get_img_name(
777 gfx_thumbnail_path_data_t *path_data, const char **img_name)
778 {
779 if (!path_data || !img_name)
780 return false;
781 if (string_is_empty(path_data->content_img))
782 return false;
783
784 *img_name = path_data->content_img;
785
786 return true;
787 }
788
789 /* Fetches current content directory.
790 * Returns true if content directory is valid. */
gfx_thumbnail_get_content_dir(gfx_thumbnail_path_data_t * path_data,char * content_dir,size_t len)791 bool gfx_thumbnail_get_content_dir(
792 gfx_thumbnail_path_data_t *path_data, char *content_dir, size_t len)
793 {
794 size_t path_length;
795 char tmp_buf[PATH_MAX_LENGTH];
796 const char *last_slash = NULL;
797
798 if (!path_data || string_is_empty(path_data->content_path))
799 return false;
800
801 last_slash = find_last_slash(path_data->content_path);
802
803 if (!last_slash)
804 return false;
805
806 path_length = last_slash + 1 - path_data->content_path;
807
808 if (!((path_length > 1) && (path_length < PATH_MAX_LENGTH)))
809 return false;
810
811 tmp_buf[0] = '\0';
812
813 strlcpy(tmp_buf, path_data->content_path, path_length * sizeof(char));
814 strlcpy(content_dir, path_basename_nocompression(tmp_buf), len);
815
816 return !string_is_empty(content_dir);
817 }
818