Blender V5.0
thumbs.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10#include <cstdlib>
11
12#include "MEM_guardedalloc.h"
13
14#include "BKE_blendfile.hh"
15
16#include "BLI_fileops.h"
17#include "BLI_ghash.h"
18#include "BLI_hash_md5.hh"
19#include "BLI_path_utils.hh"
20#include "BLI_string.h"
21#include "BLI_string_utf8.h"
22#include "BLI_string_utils.hh"
23#include "BLI_system.h"
24#include "BLI_threads.h"
25#include "BLI_utildefines.h"
26#include BLI_SYSTEM_PID_H
27
28#include "DNA_space_types.h" /* For FILE_MAX_LIBEXTRA */
29
30#include "IMB_imbuf.hh"
31#include "IMB_imbuf_types.hh"
32#include "IMB_metadata.hh"
33#include "IMB_thumbs.hh"
34
35#include "MOV_read.hh"
36
37#include <cctype>
38#include <cstring>
39#include <ctime>
40#include <sys/stat.h>
41#include <sys/types.h>
42
43#ifdef WIN32
44/* Need to include windows.h so _WIN32_IE is defined. */
45# include <windows.h>
46# ifndef _WIN32_IE
47/* Minimal requirements for SHGetSpecialFolderPath on MINGW MSVC has this defined already. */
48# define _WIN32_IE 0x0400
49# endif
50/* For SHGetSpecialFolderPath, has to be done before BLI_winstuff
51 * because 'near' is disabled through BLI_windstuff */
52# include "BLI_winstuff.h"
53# include "utfconv.hh"
54# include <direct.h> /* #chdir */
55# include <shlobj.h>
56#endif
57
58#if defined(WIN32) || defined(__APPLE__)
59/* pass */
60#else
61# define USE_FREEDESKTOP
62#endif
63
64/* '$HOME/.cache/thumbnails' or '$HOME/.thumbnails' */
65#ifdef USE_FREEDESKTOP
66# define THUMBNAILS "thumbnails"
67#else
68# define THUMBNAILS ".thumbnails"
69#endif
70
71#define URI_MAX (FILE_MAX * 3 + 8)
72
73static bool get_thumb_dir(char *dir, ThumbSize size)
74{
75 char *s = dir;
76 const char *subdir;
77#ifdef WIN32
78 wchar_t dir_16[MAX_PATH];
79 /* Yes, applications shouldn't store data there, but so does GIMP :). */
80 SHGetSpecialFolderPathW(0, dir_16, CSIDL_PROFILE, 0);
81 conv_utf_16_to_8(dir_16, dir, FILE_MAX);
82 s += strlen(dir);
83#else
84# if defined(USE_FREEDESKTOP)
85 const char *home_cache = BLI_getenv("XDG_CACHE_HOME");
86 const char *home = home_cache ? home_cache : BLI_dir_home();
87# else
88 const char *home = BLI_dir_home();
89# endif
90 if (!home) {
91 return false;
92 }
93 s += BLI_strncpy_rlen(s, home, FILE_MAX);
94
95# ifdef USE_FREEDESKTOP
96 if (!home_cache) {
97 s += BLI_strncpy_rlen(s, "/.cache", FILE_MAX - (s - dir));
98 }
99# endif
100#endif
101 switch (size) {
102 case THB_NORMAL:
103 subdir = SEP_STR THUMBNAILS SEP_STR "normal" SEP_STR;
104 break;
105 case THB_LARGE:
106 subdir = SEP_STR THUMBNAILS SEP_STR "large" SEP_STR;
107 break;
108 case THB_FAIL:
109 subdir = SEP_STR THUMBNAILS SEP_STR "fail" SEP_STR "blender" SEP_STR;
110 break;
111 default:
112 return false; /* unknown size */
113 }
114
115 s += BLI_strncpy_rlen(s, subdir, FILE_MAX - (s - dir));
116 (void)s;
117
118 return true;
119}
120
121#undef THUMBNAILS
122
123/* --- Begin of adapted code from glib. --- */
124
125/* -------------------------------------------------------------------- */
133
135 UNSAFE_ALL = 0x1, /* Escape all unsafe characters. */
136 UNSAFE_ALLOW_PLUS = 0x2, /* Allows '+' */
137 UNSAFE_PATH = 0x8, /* Allows '/', '&', '=', ':', '@', '+', '$' and ',' */
138 UNSAFE_HOST = 0x10, /* Allows '/' and ':' and '@' */
139 UNSAFE_SLASHES = 0x20, /* Allows all characters except for '/' and '%' */
140};
141
142/* Don't lose comment alignment. */
143/* clang-format off */
144static const uchar acceptable[96] = {
145 /* A table of the ASCII chars from space (32) to DEL (127) */
146 /* ! " # $ % & ' ( ) * + , - . / */
147 0x00,0x3F,0x20,0x20,0x28,0x00,0x2C,0x3F,0x3F,0x3F,0x3F,0x2A,0x28,0x3F,0x3F,0x1C,
148 /* 0 1 2 3 4 5 6 7 8 9 : ; < = > ? */
149 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x38,0x20,0x20,0x2C,0x20,0x20,
150 /* @ A B C D E F G H I J K L M N O */
151 0x38,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
152 /* P Q R S T U V W X Y Z [ \ ] ^ _ */
153 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x20,0x3F,
154 /* ` a b c d e f g h i j k l m n o */
155 0x20,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,
156 /* p q r s t u v w x y z { | } ~ DEL */
157 0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x3F,0x20,0x20,0x20,0x3F,0x20,
158};
159/* clang-format on */
160
161static const char hex[17] = "0123456789abcdef";
162
163/* NOTE: This escape function works on file: URIs, but if you want to
164 * escape something else, please read RFC-2396 */
165static void escape_uri_string(const char *string,
166 char *escaped_string,
167 const int escaped_string_size,
169{
170#define ACCEPTABLE(a) ((a) >= 32 && (a) < 128 && (acceptable[(a) - 32] & mask))
171
172 BLI_assert(escaped_string_size > 0);
173 /* Remove space for \0. */
174 int escaped_string_len = escaped_string_size - 1;
175
176 const char *p;
177 char *q;
178 int c;
179
180 for (q = escaped_string, p = string; (*p != '\0') && escaped_string_len; p++) {
181 c = uchar(*p);
182
183 if (!ACCEPTABLE(c)) {
184 if (escaped_string_len < 3) {
185 break;
186 }
187
188 *q++ = '%'; /* means hex coming */
189 *q++ = hex[c >> 4];
190 *q++ = hex[c & 15];
191 escaped_string_len -= 3;
192 }
193 else {
194 *q++ = *p;
195 escaped_string_len -= 1;
196 }
197 }
198
199 *q = '\0';
200}
201
203
204/* --- End of adapted code from glib. --- */
205
206static bool thumbhash_from_path(const char * /*path*/, ThumbSource source, char *r_hash)
207{
208 switch (source) {
209 case THB_SOURCE_FONT:
210 return IMB_thumb_load_font_get_hash(r_hash);
211 default:
212 r_hash[0] = '\0';
213 return false;
214 }
215}
216
217static bool uri_from_filepath(const char *path, char *uri)
218{
219 char orig_uri[URI_MAX];
220
221#ifdef WIN32
222 bool path_is_unc = BLI_path_is_unc(path);
223 char path_unc_normalized[FILE_MAX];
224 if (path_is_unc) {
225 STRNCPY(path_unc_normalized, path);
226 BLI_path_normalize_unc(path_unc_normalized, sizeof(path_unc_normalized));
227 path = path_unc_normalized;
228 /* Assign again because a normalized UNC path may resolve to a drive letter. */
229 path_is_unc = BLI_path_is_unc(path);
230 }
231
232 if (path_is_unc) {
233 /* Skip over the `\\` prefix, it's not needed for a URI. */
234 SNPRINTF(orig_uri, "file://%s", BLI_path_slash_skip(path));
235 }
236 else if (BLI_path_is_win32_drive(path)) {
237 SNPRINTF(orig_uri, "file:///%s", path);
238 /* Always use an uppercase drive/volume letter in the URI. */
239 orig_uri[8] = char(toupper(orig_uri[8]));
240 }
241 else {
242 /* Not a correct absolute path with a drive letter or UNC prefix. */
243 return false;
244 }
245 BLI_string_replace_char(orig_uri, '\\', '/');
246#else
247 SNPRINTF(orig_uri, "file://%s", path);
248#endif
249
250 escape_uri_string(orig_uri, uri, URI_MAX, UNSAFE_PATH);
251
252 return true;
253}
254
255static bool thumbpathname_from_uri(const char *uri,
256 char *r_path,
257 const int path_maxncpy,
258 char *r_name,
259 int name_maxncpy,
261{
262 char name_buff[40];
263
264 if (r_path && !r_name) {
265 r_name = name_buff;
266 name_maxncpy = sizeof(name_buff);
267 }
268
269 if (r_name) {
270 char hexdigest[33];
271 uchar digest[16];
272 BLI_hash_md5_buffer(uri, strlen(uri), digest);
273 hexdigest[0] = '\0';
274 BLI_snprintf(r_name, name_maxncpy, "%s.png", BLI_hash_md5_to_hexdigest(digest, hexdigest));
275 // printf("%s: '%s' --> '%s'\n", __func__, uri, r_name);
276 }
277
278 if (r_path) {
279 char tmppath[FILE_MAX];
280
281 if (get_thumb_dir(tmppath, size)) {
282 BLI_snprintf(r_path, path_maxncpy, "%s%s", tmppath, r_name);
283 // printf("%s: '%s' --> '%s'\n", __func__, uri, r_path);
284 return true;
285 }
286 }
287 return false;
288}
289
290static void thumbname_from_uri(const char *uri, char *thumb, const int thumb_maxncpy)
291{
292 thumbpathname_from_uri(uri, nullptr, 0, thumb, thumb_maxncpy, THB_FAIL);
293}
294
295static bool thumbpath_from_uri(const char *uri, char *path, const int path_maxncpy, ThumbSize size)
296{
297 return thumbpathname_from_uri(uri, path, path_maxncpy, nullptr, 0, size);
298}
299
301{
302 char tpath[FILE_MAX];
303#if 0 /* UNUSED */
304 if (get_thumb_dir(tpath, THB_NORMAL)) {
306 }
307#endif
308 if (get_thumb_dir(tpath, THB_LARGE)) {
310 }
311 if (get_thumb_dir(tpath, THB_FAIL)) {
313 }
314}
315
316/* create thumbnail for file and returns new imbuf for thumbnail */
317static ImBuf *thumb_create_ex(const char *file_path,
318 const char *uri,
319 const char *thumb,
320 const bool use_hash,
321 const char *hash,
322 const char *blen_group,
323 const char *blen_id,
325 ThumbSource source,
326 ImBuf *img)
327{
328 char desc[URI_MAX + 22];
329 char tpath[FILE_MAX];
330 char tdir[FILE_MAX];
331 char temp[FILE_MAX];
332 char mtime[40] = "0"; /* in case we can't stat the file */
333 short tsize = 128;
334 BLI_stat_t info;
335
336 switch (size) {
337 case THB_NORMAL:
339 break;
340 case THB_LARGE:
342 break;
343 case THB_FAIL:
344 tsize = 1;
345 break;
346 default:
347 return nullptr; /* unknown size */
348 }
349
350 if (get_thumb_dir(tdir, size)) {
351 SNPRINTF(tpath, "%s%s", tdir, thumb);
352 // thumb[8] = '\0'; /* shorten for `temp` name, not needed anymore */
353 SNPRINTF(temp, "%sblender_%d_%s.png", tdir, abs(getpid()), thumb);
354 if (BLI_path_ncmp(file_path, tdir, sizeof(tdir)) == 0) {
355 return nullptr;
356 }
357 if (size == THB_FAIL) {
358 img = IMB_allocImBuf(1, 1, 32, IB_byte_data | IB_metadata);
359 if (!img) {
360 return nullptr;
361 }
362 }
363 else {
365 {
366 /* only load if we didn't give an image */
367 if (img == nullptr) {
368 switch (source) {
369 case THB_SOURCE_IMAGE:
370 img = IMB_thumb_load_image(file_path, tsize, nullptr);
371 break;
372 case THB_SOURCE_BLEND:
373 img = IMB_thumb_load_blend(file_path, blen_group, blen_id);
374 break;
375 case THB_SOURCE_FONT:
376 img = IMB_thumb_load_font(file_path, tsize, tsize);
377 break;
379 if (BLI_path_extension_check(file_path, ".svg")) {
380 img = IMB_thumb_load_image(file_path, tsize, nullptr);
381 }
382 break;
383 }
384 default:
385 BLI_assert_unreachable(); /* This should never happen */
386 }
387 }
388
389 if (img != nullptr) {
390 if (BLI_stat(file_path, &info) != -1) {
391 SNPRINTF_UTF8(mtime, "%ld", (long int)info.st_mtime);
392 }
393 }
394 }
395 else if (THB_SOURCE_MOVIE == source) {
396 MovieReader *anim = nullptr;
397 /* Image buffer is converted from float to byte and only the latter one is used, and the
398 * conversion process is aware of the float colorspace. So it is possible to save some
399 * compute time by keeping the original colorspace for movies. */
400 anim = MOV_open_file(file_path, IB_byte_data | IB_metadata, 0, true, nullptr);
401 if (anim != nullptr) {
403 if (img == nullptr) {
404 // printf("not an anim; %s\n", file_path);
405 }
406 else {
407 IMB_freeImBuf(img);
408 img = MOV_decode_preview_frame(anim);
409 }
410 MOV_close(anim);
411 }
412 if (BLI_stat(file_path, &info) != -1) {
413 SNPRINTF_UTF8(mtime, "%ld", (long int)info.st_mtime);
414 }
415 }
416 if (!img) {
417 return nullptr;
418 }
419
420 if (img->x > tsize || img->y > tsize) {
421 float scale = std::min(float(tsize) / float(img->x), float(tsize) / float(img->y));
422 /* Scaling down must never assign zero width/height, see: #89868. */
423 short ex = std::max(short(1), short(img->x * scale));
424 short ey = std::max(short(1), short(img->y * scale));
425 /* Save some time by only scaling byte buffer. */
426 if (img->float_buffer.data) {
427 if (img->byte_buffer.data == nullptr) {
429 }
431 }
432 IMB_scale(img, ex, ey, IMBScaleFilter::Box, false);
433 }
434 }
435 SNPRINTF_UTF8(desc, "Thumbnail for %s", uri);
437 IMB_metadata_set_field(img->metadata, "Software", "Blender");
438 IMB_metadata_set_field(img->metadata, "Thumb::URI", uri);
439 IMB_metadata_set_field(img->metadata, "Description", desc);
440 IMB_metadata_set_field(img->metadata, "Thumb::MTime", mtime);
441 if (use_hash) {
442 IMB_metadata_set_field(img->metadata, "X-Blender::Hash", hash);
443 }
444 img->ftype = IMB_FTYPE_PNG;
445 img->planes = 32;
446
447 /* If we generated from a 16bit PNG e.g., we have a float rect, not a byte one - fix this. */
450
451 if (IMB_save_image(img, temp, IB_byte_data | IB_metadata)) {
452#ifndef WIN32
453 chmod(temp, S_IRUSR | S_IWUSR);
454#endif
455 // printf("%s saving thumb: '%s'\n", __func__, tpath);
456
457 BLI_rename_overwrite(temp, tpath);
458 }
459 }
460 return img;
461}
462
463static ImBuf *thumb_create_or_fail(const char *file_path,
464 const char *uri,
465 const char *thumb,
466 const bool use_hash,
467 const char *hash,
468 const char *blen_group,
469 const char *blen_id,
471 ThumbSource source)
472{
473 ImBuf *img = thumb_create_ex(
474 file_path, uri, thumb, use_hash, hash, blen_group, blen_id, size, source, nullptr);
475
476 if (!img) {
477 /* thumb creation failed, write fail thumb */
478 img = thumb_create_ex(
479 file_path, uri, thumb, use_hash, hash, blen_group, blen_id, THB_FAIL, source, nullptr);
480 if (img) {
481 /* we don't need failed thumb anymore */
482 IMB_freeImBuf(img);
483 img = nullptr;
484 }
485 }
486
487 return img;
488}
489
490ImBuf *IMB_thumb_create(const char *filepath, ThumbSize size, ThumbSource source, ImBuf *img)
491{
492 char uri[URI_MAX] = "";
493 char thumb_name[40];
494
495 if (!uri_from_filepath(filepath, uri)) {
496 return nullptr;
497 }
498 thumbname_from_uri(uri, thumb_name, sizeof(thumb_name));
499
500 return thumb_create_ex(
501 filepath, uri, thumb_name, false, THUMB_DEFAULT_HASH, nullptr, nullptr, size, source, img);
502}
503
504ImBuf *IMB_thumb_read(const char *file_or_lib_path, ThumbSize size)
505{
506 char thumb[FILE_MAX];
507 char uri[URI_MAX];
508 ImBuf *img = nullptr;
509
510 if (!uri_from_filepath(file_or_lib_path, uri)) {
511 return nullptr;
512 }
513 if (thumbpath_from_uri(uri, thumb, sizeof(thumb), size)) {
515 }
516
517 return img;
518}
519
520void IMB_thumb_delete(const char *file_or_lib_path, ThumbSize size)
521{
522 char thumb[FILE_MAX];
523 char uri[URI_MAX];
524
525 if (!uri_from_filepath(file_or_lib_path, uri)) {
526 return;
527 }
528 if (thumbpath_from_uri(uri, thumb, sizeof(thumb), size)) {
529 if (BLI_path_ncmp(file_or_lib_path, thumb, sizeof(thumb)) == 0) {
530 return;
531 }
532 if (BLI_exists(thumb)) {
533 BLI_delete(thumb, false, false);
534 }
535 }
536}
537
538ImBuf *IMB_thumb_manage(const char *file_or_lib_path, ThumbSize size, ThumbSource source)
539{
540 char path_buff[FILE_MAX_LIBEXTRA];
541 char *blen_group = nullptr, *blen_id = nullptr;
542
543 /* Will be the actual path to the file, i.e. the same as #file_or_lib_path, or if that points
544 * into a .blend, the path of the .blend. */
545 const char *file_path = file_or_lib_path;
546 if (source == THB_SOURCE_BLEND) {
547 if (BKE_blendfile_library_path_explode(file_or_lib_path, path_buff, &blen_group, &blen_id)) {
548 if (blen_group) {
549 if (!blen_id) {
550 /* No preview for blen groups */
551 return nullptr;
552 }
553 file_path = path_buff; /* path needs to be a valid file! */
554 }
555 }
556 }
557
558 BLI_stat_t st;
559 if (BLI_stat(file_path, &st) == -1) {
560 return nullptr;
561 }
562 char uri[URI_MAX];
563 if (!uri_from_filepath(file_or_lib_path, uri)) {
564 return nullptr;
565 }
566
567 /* Don't access offline files, only use already existing thumbnails (don't recreate). */
568 const eFileAttributes file_attributes = BLI_file_attributes(file_path);
569 if (file_attributes & FILE_ATTR_OFFLINE) {
570 char thumb_path[FILE_MAX];
571 if (thumbpath_from_uri(uri, thumb_path, sizeof(thumb_path), size)) {
573 }
574 return nullptr;
575 }
576
577 char thumb_path[FILE_MAX];
578 if (thumbpath_from_uri(uri, thumb_path, sizeof(thumb_path), THB_FAIL)) {
579 /* failure thumb exists, don't try recreating */
580 if (BLI_exists(thumb_path)) {
581 /* clear out of date fail case (note for blen IDs we use blender file itself here) */
582 if (BLI_file_older(thumb_path, file_path)) {
583 BLI_delete(thumb_path, false, false);
584 }
585 else {
586 return nullptr;
587 }
588 }
589 }
590
591 ImBuf *img = nullptr;
592 char thumb_name[40];
594 uri, thumb_path, sizeof(thumb_path), thumb_name, sizeof(thumb_name), size))
595 {
596 /* The requested path points to a generated thumbnail already (path into the thumbnail cache
597 * directory). Attempt to load that, there's nothing we can recreate. */
598 if (BLI_path_ncmp(file_or_lib_path, thumb_path, sizeof(thumb_path)) == 0) {
599 img = IMB_load_image_from_filepath(file_or_lib_path, IB_byte_data);
600 }
601 else {
603 if (img) {
604 bool regenerate = false;
605
606 char mtime[40];
607 char thumb_hash[33];
608 char thumb_hash_curr[33];
609
610 const bool use_hash = thumbhash_from_path(file_path, source, thumb_hash);
611
612 if (IMB_metadata_get_field(img->metadata, "Thumb::MTime", mtime, sizeof(mtime))) {
613 regenerate = (st.st_mtime != atol(mtime));
614 }
615 else {
616 /* illegal thumb, regenerate it! */
617 regenerate = true;
618 }
619
620 if (use_hash && !regenerate) {
622 img->metadata, "X-Blender::Hash", thumb_hash_curr, sizeof(thumb_hash_curr)))
623 {
624 regenerate = !STREQ(thumb_hash, thumb_hash_curr);
625 }
626 else {
627 regenerate = true;
628 }
629 }
630
631 if (regenerate) {
632 /* recreate all thumbs */
633 IMB_freeImBuf(img);
634 img = nullptr;
635 IMB_thumb_delete(file_or_lib_path, THB_NORMAL);
636 IMB_thumb_delete(file_or_lib_path, THB_LARGE);
637 IMB_thumb_delete(file_or_lib_path, THB_FAIL);
639 file_path, uri, thumb_name, use_hash, thumb_hash, blen_group, blen_id, size, source);
640 }
641 }
642 else {
643 char thumb_hash[33];
644 const bool use_hash = thumbhash_from_path(file_path, source, thumb_hash);
645
647 file_path, uri, thumb_name, use_hash, thumb_hash, blen_group, blen_id, size, source);
648 }
649 }
650 }
651
652 /* Our imbuf **must** have a valid rect (i.e. 8-bits/channels)
653 * data, we rely on this in draw code.
654 * However, in some cases we may end loading 16bits PNGs, which generated float buffers.
655 * This should be taken care of in generation step, but add also a safeguard here! */
656 if (img) {
659 }
660
661 return img;
662}
663
664/* ***** Threading ***** */
665/* Thumbnail handling is not really threadsafe in itself.
666 * However, as long as we do not operate on the same file, we shall have no collision.
667 * So idea is to 'lock' a given source file path.
668 */
669
675
677{
679
680 if (thumb_locks.lock_counter == 0) {
681 BLI_assert(thumb_locks.locked_paths == nullptr);
682 thumb_locks.locked_paths = BLI_gset_str_new(__func__);
684 }
685 thumb_locks.lock_counter++;
686
687 BLI_assert(thumb_locks.locked_paths != nullptr);
688 BLI_assert(thumb_locks.lock_counter > 0);
690}
691
693{
695 BLI_assert((thumb_locks.locked_paths != nullptr) && (thumb_locks.lock_counter > 0));
696
697 thumb_locks.lock_counter--;
698 if (thumb_locks.lock_counter == 0) {
699 BLI_gset_free(thumb_locks.locked_paths, MEM_freeN);
700 thumb_locks.locked_paths = nullptr;
702 }
703
705}
706
707void IMB_thumb_path_lock(const char *path)
708{
709 void *key = BLI_strdup(path);
710
712 BLI_assert((thumb_locks.locked_paths != nullptr) && (thumb_locks.lock_counter > 0));
713
714 if (thumb_locks.locked_paths) {
715 while (!BLI_gset_add(thumb_locks.locked_paths, key)) {
717 }
718 }
719
721}
722
723void IMB_thumb_path_unlock(const char *path)
724{
725 const void *key = path;
726
728 BLI_assert((thumb_locks.locked_paths != nullptr) && (thumb_locks.lock_counter > 0));
729
730 if (thumb_locks.locked_paths) {
731 if (!BLI_gset_remove(thumb_locks.locked_paths, key, MEM_freeN)) {
733 }
735 }
736
738}
bool BKE_blendfile_library_path_explode(const char *path, char *r_dir, char **r_group, char **r_name)
Definition blendfile.cc:92
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
File and directory operations.
eFileAttributes BLI_file_attributes(const char *path)
Definition storage.cc:237
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:360
bool BLI_file_older(const char *file1, const char *file2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:614
int BLI_stat(const char *path, BLI_stat_t *buffer) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
bool BLI_dir_create_recursive(const char *dirname) ATTR_NONNULL()
Definition fileops_c.cc:414
int BLI_delete(const char *path, bool dir, bool recursive) ATTR_NONNULL()
struct stat BLI_stat_t
int BLI_rename_overwrite(const char *from, const char *to) ATTR_NONNULL()
Definition fileops_c.cc:528
eFileAttributes
@ FILE_ATTR_OFFLINE
const char * BLI_dir_home(void)
Definition storage.cc:97
struct GSet GSet
Definition BLI_ghash.h:337
GSet * BLI_gset_str_new(const char *info)
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
bool BLI_gset_add(GSet *gs, void *key)
Definition BLI_ghash.cc:966
bool BLI_gset_remove(GSet *gs, const void *key, GSetKeyFreeFP keyfreefp)
Definition BLI_ghash.cc:999
char * BLI_hash_md5_to_hexdigest(const void *resblock, char r_hex_digest[33])
Definition hash_md5.cc:379
void * BLI_hash_md5_buffer(const char *buffer, size_t len, void *resblock)
Definition hash_md5.cc:343
#define BLI_path_ncmp
#define FILE_MAX
const char * BLI_getenv(const char *env) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
bool BLI_path_is_win32_drive(const char *path)
const char * BLI_path_slash_skip(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
bool BLI_path_extension_check(const char *path, const char *ext) ATTR_NONNULL(1
bool BLI_path_is_unc(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:604
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
size_t BLI_snprintf(char *__restrict dst, size_t dst_maxncpy, const char *__restrict format,...) ATTR_NONNULL(1
char char size_t BLI_strncpy_rlen(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
#define SNPRINTF_UTF8(dst, format,...)
void BLI_string_replace_char(char *str, char src, char dst) ATTR_NONNULL(1)
unsigned char uchar
void BLI_condition_notify_all(ThreadCondition *cond)
Definition threads.cc:595
void BLI_thread_unlock(int type)
Definition threads.cc:333
void BLI_thread_lock(int type)
Definition threads.cc:328
void BLI_condition_wait_global_mutex(ThreadCondition *cond, int type)
Definition threads.cc:585
pthread_cond_t ThreadCondition
void BLI_condition_end(ThreadCondition *cond)
Definition threads.cc:600
void BLI_condition_init(ThreadCondition *cond)
Definition threads.cc:575
@ LOCK_IMAGE
Definition BLI_threads.h:63
#define ELEM(...)
#define STREQ(a, b)
Compatibility-like things for windows.
#define FILE_MAX_LIBEXTRA
ImBuf * IMB_load_image_from_filepath(const char *filepath, const int flags, char r_colorspace[IM_MAX_SPACE]=nullptr)
Definition readimage.cc:189
ImBuf * IMB_thumb_load_image(const char *filepath, const size_t max_thumb_size, char colorspace[IM_MAX_SPACE], const IMBThumbLoadFlags load_flags=IMBThumbLoadFlags::Zero)
Definition readimage.cc:214
void IMB_byte_from_float(ImBuf *ibuf)
void IMB_freeImBuf(ImBuf *ibuf)
ImBuf * IMB_allocImBuf(unsigned int x, unsigned int y, unsigned char planes, unsigned int flags)
void IMB_free_float_pixels(ImBuf *ibuf)
bool IMB_save_image(ImBuf *ibuf, const char *filepath, const int flags)
Definition writeimage.cc:23
bool IMB_scale(ImBuf *ibuf, unsigned int newx, unsigned int newy, IMBScaleFilter filter, bool threaded=true)
Definition scaling.cc:465
@ IMB_FTYPE_PNG
@ IMB_PROXY_NONE
@ IB_byte_data
@ IB_metadata
void IMB_metadata_set_field(IDProperty *metadata, const char *key, const char *value)
Definition metadata.cc:68
bool IMB_metadata_get_field(const IDProperty *metadata, const char *key, char *value, size_t value_maxncpy)
Definition metadata.cc:41
void IMB_metadata_ensure(IDProperty **metadata)
Definition metadata.cc:23
#define PREVIEW_RENDER_DEFAULT_HEIGHT
Definition IMB_thumbs.hh:40
ThumbSize
Definition IMB_thumbs.hh:21
@ THB_FAIL
Definition IMB_thumbs.hh:24
@ THB_NORMAL
Definition IMB_thumbs.hh:22
@ THB_LARGE
Definition IMB_thumbs.hh:23
bool IMB_thumb_load_font_get_hash(char *r_hash)
ThumbSource
Definition IMB_thumbs.hh:27
@ THB_SOURCE_IMAGE
Definition IMB_thumbs.hh:28
@ THB_SOURCE_FONT
Definition IMB_thumbs.hh:31
@ THB_SOURCE_BLEND
Definition IMB_thumbs.hh:30
@ THB_SOURCE_MOVIE
Definition IMB_thumbs.hh:29
@ THB_SOURCE_OBJECT_IO
Definition IMB_thumbs.hh:32
#define PREVIEW_RENDER_LARGE_HEIGHT
Definition IMB_thumbs.hh:41
ImBuf * IMB_thumb_load_blend(const char *blen_path, const char *blen_group, const char *blen_id)
ImBuf * IMB_thumb_load_font(const char *filepath, unsigned int x, unsigned int y)
#define THUMB_DEFAULT_HASH
Definition IMB_thumbs.hh:48
Read Guarded memory(de)allocation.
@ IMB_TC_NONE
Definition MOV_enums.hh:46
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
#define abs
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
ImBuf * MOV_decode_preview_frame(MovieReader *anim)
void MOV_close(MovieReader *anim)
Definition movie_read.cc:66
MovieReader * MOV_open_file(const char *filepath, const int ib_flags, const int streamindex, const bool keep_original_colorspace, char colorspace[IM_MAX_SPACE])
ImBuf * MOV_decode_frame(MovieReader *anim, int position, IMB_Timecode_Type tc, IMB_Proxy_Size preview_size)
#define hash
Definition noise_c.cc:154
ThreadCondition cond
Definition thumbs.cc:673
int lock_counter
Definition thumbs.cc:672
GSet * locked_paths
Definition thumbs.cc:671
ImBufFloatBuffer float_buffer
ImBufByteBuffer byte_buffer
unsigned char planes
enum eImbFileType ftype
IDProperty * metadata
static bool uri_from_filepath(const char *path, char *uri)
Definition thumbs.cc:217
static bool thumbpathname_from_uri(const char *uri, char *r_path, const int path_maxncpy, char *r_name, int name_maxncpy, ThumbSize size)
Definition thumbs.cc:255
static ImBuf * thumb_create_or_fail(const char *file_path, const char *uri, const char *thumb, const bool use_hash, const char *hash, const char *blen_group, const char *blen_id, ThumbSize size, ThumbSource source)
Definition thumbs.cc:463
ImBuf * IMB_thumb_create(const char *filepath, ThumbSize size, ThumbSource source, ImBuf *img)
Definition thumbs.cc:490
ImBuf * IMB_thumb_read(const char *file_or_lib_path, ThumbSize size)
Definition thumbs.cc:504
void IMB_thumb_delete(const char *file_or_lib_path, ThumbSize size)
Definition thumbs.cc:520
static void thumbname_from_uri(const char *uri, char *thumb, const int thumb_maxncpy)
Definition thumbs.cc:290
void IMB_thumb_path_unlock(const char *path)
Definition thumbs.cc:723
void IMB_thumb_locks_acquire()
Definition thumbs.cc:676
ImBuf * IMB_thumb_manage(const char *file_or_lib_path, ThumbSize size, ThumbSource source)
Definition thumbs.cc:538
void IMB_thumb_path_lock(const char *path)
Definition thumbs.cc:707
#define URI_MAX
Definition thumbs.cc:71
static void escape_uri_string(const char *string, char *escaped_string, const int escaped_string_size, const eUnsafeCharacterSet mask)
Definition thumbs.cc:165
static const uchar acceptable[96]
Definition thumbs.cc:144
static const char hex[17]
Definition thumbs.cc:161
static bool thumbhash_from_path(const char *, ThumbSource source, char *r_hash)
Definition thumbs.cc:206
#define THUMBNAILS
Definition thumbs.cc:66
#define ACCEPTABLE(a)
static bool thumbpath_from_uri(const char *uri, char *path, const int path_maxncpy, ThumbSize size)
Definition thumbs.cc:295
void IMB_thumb_locks_release()
Definition thumbs.cc:692
static struct IMBThumbLocks thumb_locks
eUnsafeCharacterSet
Definition thumbs.cc:134
@ UNSAFE_HOST
Definition thumbs.cc:138
@ UNSAFE_ALLOW_PLUS
Definition thumbs.cc:136
@ UNSAFE_ALL
Definition thumbs.cc:135
@ UNSAFE_PATH
Definition thumbs.cc:137
@ UNSAFE_SLASHES
Definition thumbs.cc:139
static ImBuf * thumb_create_ex(const char *file_path, const char *uri, const char *thumb, const bool use_hash, const char *hash, const char *blen_group, const char *blen_id, ThumbSize size, ThumbSource source, ImBuf *img)
Definition thumbs.cc:317
void IMB_thumb_makedirs()
Definition thumbs.cc:300
static bool get_thumb_dir(char *dir, ThumbSize size)
Definition thumbs.cc:73
#define SEP_STR
Definition unit.cc:39
int conv_utf_16_to_8(const wchar_t *in16, char *out8, size_t size8)
Definition utfconv.cc:116