Blender V4.3
packedFile.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include <cstdio>
10#include <fcntl.h>
11#include <sys/stat.h>
12
13#ifndef WIN32
14# include <unistd.h>
15#else
16# include <io.h>
17#endif
18#include "MEM_guardedalloc.h"
19#include <cstring>
20
21#include "DNA_ID.h"
22#include "DNA_image_types.h"
23#include "DNA_modifier_types.h"
25#include "DNA_sound_types.h"
26#include "DNA_vfont_types.h"
27#include "DNA_volume_types.h"
28
29#include "BLI_blenlib.h"
30#include "BLI_utildefines.h"
31
34#include "BKE_image.hh"
35#include "BKE_image_format.hh"
36#include "BKE_main.hh"
37#include "BKE_packedFile.hh"
38#include "BKE_report.hh"
39#include "BKE_sound.h"
40#include "BKE_vfont.hh"
41#include "BKE_volume.hh"
42
43#include "DEG_depsgraph.hh"
44
45#include "IMB_imbuf.hh"
46#include "IMB_imbuf_types.hh"
47
48#include "MOD_nodes.hh"
49
50#include "BLO_read_write.hh"
51
52#include "CLG_log.h"
53
54static CLG_LogRef LOG = {"bke.packedfile"};
55
56using namespace blender;
57
58int BKE_packedfile_seek(PackedFile *pf, int offset, int whence)
59{
60 int oldseek = -1, seek = 0;
61
62 if (pf) {
63 oldseek = pf->seek;
64 switch (whence) {
65 case SEEK_CUR:
66 seek = oldseek + offset;
67 break;
68 case SEEK_END:
69 seek = pf->size + offset;
70 break;
71 case SEEK_SET:
72 seek = offset;
73 break;
74 default:
75 oldseek = -1;
76 break;
77 }
78 if (seek < 0) {
79 seek = 0;
80 }
81 else if (seek > pf->size) {
82 seek = pf->size;
83 }
84 pf->seek = seek;
85 }
86
87 return oldseek;
88}
89
91{
92 BKE_packedfile_seek(pf, 0, SEEK_SET);
93}
94
95int BKE_packedfile_read(PackedFile *pf, void *data, int size)
96{
97 if ((pf != nullptr) && (size >= 0) && (data != nullptr)) {
98 if (size + pf->seek > pf->size) {
99 size = pf->size - pf->seek;
100 }
101
102 if (size > 0) {
103 memcpy(data, ((const char *)pf->data) + pf->seek, size);
104 }
105 else {
106 size = 0;
107 }
108
109 pf->seek += size;
110 }
111 else {
112 size = -1;
113 }
114
115 return size;
116}
117
119{
120 Image *ima;
121 VFont *vf;
122 bSound *sound;
123 Volume *volume;
124
126
127 /* let's check if there are packed files... */
128 for (ima = static_cast<Image *>(bmain->images.first); ima;
129 ima = static_cast<Image *>(ima->id.next))
130 {
131 if (BKE_image_has_packedfile(ima) && !ID_IS_LINKED(ima)) {
133 }
134 }
135
136 for (vf = static_cast<VFont *>(bmain->fonts.first); vf; vf = static_cast<VFont *>(vf->id.next)) {
137 if (vf->packedfile && !ID_IS_LINKED(vf)) {
138 count.individual_files++;
139 }
140 }
141
142 for (sound = static_cast<bSound *>(bmain->sounds.first); sound;
143 sound = static_cast<bSound *>(sound->id.next))
144 {
145 if (sound->packedfile && !ID_IS_LINKED(sound)) {
146 count.individual_files++;
147 }
148 }
149
150 for (volume = static_cast<Volume *>(bmain->volumes.first); volume;
151 volume = static_cast<Volume *>(volume->id.next))
152 {
153 if (volume->packedfile && !ID_IS_LINKED(volume)) {
154 count.individual_files++;
155 }
156 }
157
158 LISTBASE_FOREACH (Object *, object, &bmain->objects) {
159 if (ID_IS_LINKED(object)) {
160 continue;
161 }
162 LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
163 if (md->type == eModifierType_Nodes) {
164 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
165 for (const NodesModifierBake &bake : blender::Span{nmd->bakes, nmd->bakes_num}) {
166 if (bake.packed) {
167 count.bakes++;
168 }
169 }
170 }
171 }
172 }
173
174 return count;
175}
176
178{
179 if (pf) {
180 BLI_assert(pf->data != nullptr);
181 BLI_assert(pf->sharing_info != nullptr);
182
183 pf->sharing_info->remove_user_and_delete_if_last();
184 MEM_freeN(pf);
185 }
186 else {
187 printf("%s: Trying to free a nullptr pointer\n", __func__);
188 }
189}
190
192{
193 BLI_assert(pf_src != nullptr);
194 BLI_assert(pf_src->data != nullptr);
195
196 PackedFile *pf_dst;
197
198 pf_dst = static_cast<PackedFile *>(MEM_dupallocN(pf_src));
199 pf_dst->sharing_info->add_user();
200
201 return pf_dst;
202}
203
205 int memlen,
206 const blender::ImplicitSharingInfo *sharing_info)
207{
208 BLI_assert(mem != nullptr);
209 if (!sharing_info) {
210 /* Assume we are the only owner of that memory currently. */
211 sharing_info = blender::implicit_sharing::info_for_mem_free(const_cast<void *>(mem));
212 }
213
214 PackedFile *pf = static_cast<PackedFile *>(MEM_callocN(sizeof(*pf), "PackedFile"));
215 pf->data = mem;
216 pf->size = memlen;
217 pf->sharing_info = sharing_info;
218
219 return pf;
220}
221
222PackedFile *BKE_packedfile_new(ReportList *reports, const char *filepath_rel, const char *basepath)
223{
224 char filepath[FILE_MAX];
225
226 /* render result has no filepath and can be ignored
227 * any other files with no name can be ignored too */
228 if (filepath_rel[0] == '\0') {
229 return nullptr;
230 }
231
232 // XXX waitcursor(1);
233
234 /* convert relative filenames to absolute filenames */
235
236 STRNCPY(filepath, filepath_rel);
237 BLI_path_abs(filepath, basepath);
238
239 /* open the file
240 * and create a PackedFile structure */
241
242 const int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
243 if (file == -1) {
244 BKE_reportf(reports, RPT_ERROR, "Unable to pack file, source path '%s' not found", filepath);
245 return nullptr;
246 }
247
248 PackedFile *pf = nullptr;
249 const size_t file_size = BLI_file_descriptor_size(file);
250 if (file_size == size_t(-1)) {
251 BKE_reportf(reports, RPT_ERROR, "Unable to access the size of, source path '%s'", filepath);
252 }
253 else if (file_size > INT_MAX) {
254 BKE_reportf(reports, RPT_ERROR, "Unable to pack files over 2gb, source path '%s'", filepath);
255 }
256 else {
257 /* #MEM_mallocN complains about `MEM_mallocN(0, "...")`,
258 * a single allocation is harmless and doesn't cause any complications. */
259 void *data = MEM_mallocN(std::max(file_size, size_t(1)), "packFile");
260 if (BLI_read(file, data, file_size) == file_size) {
261 pf = BKE_packedfile_new_from_memory(data, file_size);
262 }
263 else {
264 MEM_freeN(data);
265 }
266 }
267
268 close(file);
269
270 // XXX waitcursor(0);
271
272 return pf;
273}
274
275void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose)
276{
277 Image *ima;
278 VFont *vfont;
279 bSound *sound;
280 Volume *volume;
281 int tot = 0;
282
283 for (ima = static_cast<Image *>(bmain->images.first); ima;
284 ima = static_cast<Image *>(ima->id.next))
285 {
286 if (BKE_image_has_packedfile(ima) == false && ID_IS_EDITABLE(ima)) {
288 BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
289 tot++;
290 }
291 else if (ELEM(ima->source, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE) && verbose) {
292 BKE_reportf(reports,
294 "Image '%s' skipped, packing movies or image sequences not supported",
295 ima->id.name + 2);
296 }
297 }
298 }
299
300 for (vfont = static_cast<VFont *>(bmain->fonts.first); vfont;
301 vfont = static_cast<VFont *>(vfont->id.next))
302 {
303 if (vfont->packedfile == nullptr && ID_IS_EDITABLE(vfont) &&
304 BKE_vfont_is_builtin(vfont) == false)
305 {
307 reports, vfont->filepath, BKE_main_blendfile_path(bmain));
308 tot++;
309 }
310 }
311
312 for (sound = static_cast<bSound *>(bmain->sounds.first); sound;
313 sound = static_cast<bSound *>(sound->id.next))
314 {
315 if (sound->packedfile == nullptr && ID_IS_EDITABLE(sound)) {
317 reports, sound->filepath, BKE_main_blendfile_path(bmain));
318 tot++;
319 }
320 }
321
322 for (volume = static_cast<Volume *>(bmain->volumes.first); volume;
323 volume = static_cast<Volume *>(volume->id.next))
324 {
325 if (volume->packedfile == nullptr && ID_IS_EDITABLE(volume)) {
326 volume->packedfile = BKE_packedfile_new(
327 reports, volume->filepath, BKE_main_blendfile_path(bmain));
328 tot++;
329 }
330 }
331
332 LISTBASE_FOREACH (Object *, object, &bmain->objects) {
333 if (ID_IS_LINKED(object)) {
334 continue;
335 }
336 LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
337 if (md->type == eModifierType_Nodes) {
338 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
340 blender::bke::bake::pack_geometry_nodes_bake(*bmain, reports, *object, *nmd, bake);
341 }
342 }
343 }
344 }
345
346 if (tot > 0) {
347 BKE_reportf(reports, RPT_INFO, "Packed %d file(s)", tot);
348 }
349 else if (verbose) {
350 BKE_report(reports, RPT_INFO, "No new files have been packed");
351 }
352}
353
355 const char *ref_file_name,
356 const char *filepath_rel,
357 PackedFile *pf)
358{
359 int file, number;
360 int ret_value = RET_OK;
361 bool remove_tmp = false;
362 char filepath[FILE_MAX];
363 char filepath_temp[FILE_MAX];
364 // void *data;
365
366 STRNCPY(filepath, filepath_rel);
367 BLI_path_abs(filepath, ref_file_name);
368
369 if (BLI_exists(filepath)) {
370 for (number = 1; number <= 999; number++) {
371 SNPRINTF(filepath_temp, "%s.%03d_", filepath, number);
372 if (!BLI_exists(filepath_temp)) {
373 if (BLI_copy(filepath, filepath_temp) == RET_OK) {
374 remove_tmp = true;
375 }
376 break;
377 }
378 }
379 }
380
382
383 file = BLI_open(filepath, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666);
384 if (file == -1) {
385 BKE_reportf(reports, RPT_ERROR, "Error creating file '%s'", filepath);
386 ret_value = RET_ERROR;
387 }
388 else {
389 if (write(file, pf->data, pf->size) != pf->size) {
390 BKE_reportf(reports, RPT_ERROR, "Error writing file '%s'", filepath);
391 ret_value = RET_ERROR;
392 }
393 else {
394 BKE_reportf(reports, RPT_INFO, "Saved packed file to: %s", filepath);
395 }
396
397 close(file);
398 }
399
400 if (remove_tmp) {
401 if (ret_value == RET_ERROR) {
402 if (BLI_rename_overwrite(filepath_temp, filepath) != 0) {
403 BKE_reportf(reports,
404 RPT_ERROR,
405 "Error restoring temp file (check files '%s' '%s')",
406 filepath_temp,
407 filepath);
408 }
409 }
410 else {
411 if (BLI_delete(filepath_temp, false, false) != 0) {
412 BKE_reportf(reports, RPT_ERROR, "Error deleting '%s' (ignored)", filepath_temp);
413 }
414 }
415 }
416
417 return ret_value;
418}
419
420enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name,
421 const char *filepath_rel,
422 const PackedFile *pf)
423{
424 BLI_stat_t st;
425 enum ePF_FileCompare ret_val;
426 char buf[4096];
427 char filepath[FILE_MAX];
428
429 STRNCPY(filepath, filepath_rel);
430 BLI_path_abs(filepath, ref_file_name);
431
432 if (BLI_stat(filepath, &st) == -1) {
433 ret_val = PF_CMP_NOFILE;
434 }
435 else if (st.st_size != pf->size) {
436 ret_val = PF_CMP_DIFFERS;
437 }
438 else {
439 /* we'll have to compare the two... */
440
441 const int file = BLI_open(filepath, O_BINARY | O_RDONLY, 0);
442 if (file == -1) {
443 ret_val = PF_CMP_NOFILE;
444 }
445 else {
446 ret_val = PF_CMP_EQUAL;
447
448 for (int i = 0; i < pf->size; i += sizeof(buf)) {
449 int len = pf->size - i;
450 if (len > sizeof(buf)) {
451 len = sizeof(buf);
452 }
453
454 if (BLI_read(file, buf, len) != len) {
455 /* read error ... */
456 ret_val = PF_CMP_DIFFERS;
457 break;
458 }
459
460 if (memcmp(buf, ((const char *)pf->data) + i, len) != 0) {
461 ret_val = PF_CMP_DIFFERS;
462 break;
463 }
464 }
465
466 close(file);
467 }
468 }
469
470 return ret_val;
471}
472
474 const char *ref_file_name,
475 const char *abs_name,
476 const char *local_name,
477 PackedFile *pf,
478 enum ePF_FileStatus how)
479{
480 char *newname = nullptr;
481 const char *temp = nullptr;
482
483 if (pf != nullptr) {
484 switch (how) {
485 case PF_KEEP:
486 break;
487 case PF_REMOVE:
488 temp = abs_name;
489 break;
490 case PF_USE_LOCAL: {
491 char temp_abs[FILE_MAX];
492
493 STRNCPY(temp_abs, local_name);
494 BLI_path_abs(temp_abs, ref_file_name);
495
496 /* if file exists use it */
497 if (BLI_exists(temp_abs)) {
498 temp = local_name;
499 break;
500 }
501 /* else create it */
503 }
504 case PF_WRITE_LOCAL:
505 if (BKE_packedfile_write_to_file(reports, ref_file_name, local_name, pf) == RET_OK) {
506 temp = local_name;
507 }
508 break;
509 case PF_USE_ORIGINAL: {
510 char temp_abs[FILE_MAX];
511
512 STRNCPY(temp_abs, abs_name);
513 BLI_path_abs(temp_abs, ref_file_name);
514
515 /* if file exists use it */
516 if (BLI_exists(temp_abs)) {
517 BKE_reportf(reports, RPT_INFO, "Use existing file (instead of packed): %s", abs_name);
518 temp = abs_name;
519 break;
520 }
521 /* else create it */
523 }
525 if (BKE_packedfile_write_to_file(reports, ref_file_name, abs_name, pf) == RET_OK) {
526 temp = abs_name;
527 }
528 break;
529 default:
530 printf("%s: unknown return_value %d\n", __func__, how);
531 break;
532 }
533
534 if (temp) {
535 newname = BLI_strdup(temp);
536 }
537 }
538
539 return newname;
540}
541
542static void unpack_generate_paths(const char *filepath,
543 ID *id,
544 char *r_abspath,
545 size_t abspath_maxncpy,
546 char *r_relpath,
547 size_t relpath_maxncpy)
548{
549 const short id_type = GS(id->name);
550 char temp_filename[FILE_MAX];
551 char temp_dirname[FILE_MAXDIR];
552
554 filepath, temp_dirname, sizeof(temp_dirname), temp_filename, sizeof(temp_filename));
555
556 if (temp_filename[0] == '\0') {
557 /* NOTE: we generally do not have any real way to re-create extension out of data. */
558 const size_t len = STRNCPY_RLEN(temp_filename, id->name + 2);
559 printf("%s\n", temp_filename);
560
561 /* For images ensure that the temporary filename contains tile number information as well as
562 * a file extension based on the file magic. */
563 if (id_type == ID_IM) {
564 Image *ima = (Image *)id;
565 ImagePackedFile *imapf = static_cast<ImagePackedFile *>(ima->packedfiles.last);
566 if (imapf != nullptr && imapf->packedfile != nullptr) {
567 const PackedFile *pf = imapf->packedfile;
568 enum eImbFileType ftype = eImbFileType(
569 IMB_ispic_type_from_memory((const uchar *)pf->data, pf->size));
570 if (ima->source == IMA_SRC_TILED) {
571 char tile_number[6];
572 SNPRINTF(tile_number, ".%d", imapf->tile_number);
573 BLI_strncpy(temp_filename + len, tile_number, sizeof(temp_filename) - len);
574 }
575 if (ftype != IMB_FTYPE_NONE) {
576 const int imtype = BKE_ftype_to_imtype(ftype, nullptr);
577 BKE_image_path_ext_from_imtype_ensure(temp_filename, sizeof(temp_filename), imtype);
578 }
579 }
580 }
581
582 BLI_path_make_safe_filename(temp_filename);
583 printf("%s\n", temp_filename);
584 }
585
586 if (temp_dirname[0] == '\0') {
587 /* Fallback to relative dir. */
588 STRNCPY(temp_dirname, "//");
589 }
590
591 {
592 const char *dir_name = nullptr;
593 switch (id_type) {
594 case ID_VF:
595 dir_name = "fonts";
596 break;
597 case ID_SO:
598 dir_name = "sounds";
599 break;
600 case ID_IM:
601 dir_name = "textures";
602 break;
603 case ID_VO:
604 dir_name = "volumes";
605 break;
606 default:
607 break;
608 }
609 if (dir_name) {
610 BLI_path_join(r_relpath, relpath_maxncpy, "//", dir_name, temp_filename);
611 }
612 }
613
614 {
615 size_t len = BLI_strncpy_rlen(r_abspath, temp_dirname, abspath_maxncpy);
616 BLI_strncpy(r_abspath + len, temp_filename, abspath_maxncpy - len);
617 }
618}
619
621 ReportList *reports,
622 ID *id,
623 const char *orig_file_path,
624 PackedFile *pf,
625 enum ePF_FileStatus how)
626{
627 char localname[FILE_MAX], absname[FILE_MAX];
628 char *new_name = nullptr;
629
630 if (id != nullptr) {
632 orig_file_path, id, absname, sizeof(absname), localname, sizeof(localname));
634 reports, BKE_main_blendfile_path(bmain), absname, localname, pf, how);
635 }
636
637 return new_name;
638}
639
641 ReportList *reports,
642 VFont *vfont,
643 enum ePF_FileStatus how)
644{
645 int ret_value = RET_ERROR;
646 if (vfont) {
647 char *new_file_path = BKE_packedfile_unpack(
648 bmain, reports, (ID *)vfont, vfont->filepath, vfont->packedfile, how);
649
650 if (new_file_path != nullptr) {
651 ret_value = RET_OK;
652 BKE_packedfile_free(vfont->packedfile);
653 vfont->packedfile = nullptr;
654 STRNCPY(vfont->filepath, new_file_path);
655 MEM_freeN(new_file_path);
656 }
657 }
658
659 return ret_value;
660}
661
663 ReportList *reports,
664 bSound *sound,
665 enum ePF_FileStatus how)
666{
667 int ret_value = RET_ERROR;
668
669 if (sound != nullptr) {
670 char *new_file_path = BKE_packedfile_unpack(
671 bmain, reports, (ID *)sound, sound->filepath, sound->packedfile, how);
672 if (new_file_path != nullptr) {
673 STRNCPY(sound->filepath, new_file_path);
674 MEM_freeN(new_file_path);
675
676 BKE_packedfile_free(sound->packedfile);
677 sound->packedfile = nullptr;
678
679 BKE_sound_load(bmain, sound);
680
681 ret_value = RET_OK;
682 }
683 }
684
685 return ret_value;
686}
687
689 ReportList *reports,
690 Image *ima,
691 enum ePF_FileStatus how)
692{
693 int ret_value = RET_ERROR;
694
695 if (ima != nullptr) {
696 while (ima->packedfiles.last) {
697 ImagePackedFile *imapf = static_cast<ImagePackedFile *>(ima->packedfiles.last);
698 char *new_file_path = BKE_packedfile_unpack(
699 bmain, reports, (ID *)ima, imapf->filepath, imapf->packedfile, how);
700
701 if (new_file_path != nullptr) {
702 ImageView *iv;
703
704 ret_value = ret_value == RET_ERROR ? RET_ERROR : RET_OK;
706 imapf->packedfile = nullptr;
707
708 /* update the new corresponding view filepath */
709 iv = static_cast<ImageView *>(
710 BLI_findstring(&ima->views, imapf->filepath, offsetof(ImageView, filepath)));
711 if (iv) {
712 STRNCPY(iv->filepath, new_file_path);
713 }
714
715 /* keep the new name in the image for non-pack specific reasons */
716 if (how != PF_REMOVE) {
717 STRNCPY(ima->filepath, new_file_path);
718 if (ima->source == IMA_SRC_TILED) {
719 /* Ensure that the Image filepath is kept in a tokenized format. */
720 BKE_image_ensure_tile_token(ima->filepath, sizeof(ima->filepath));
721 }
722 }
723 MEM_freeN(new_file_path);
724 }
725 else {
726 ret_value = RET_ERROR;
727 }
728
729 BLI_remlink(&ima->packedfiles, imapf);
730 MEM_freeN(imapf);
731 }
732 }
733
734 if (ret_value == RET_OK) {
735 BKE_image_signal(bmain, ima, nullptr, IMA_SIGNAL_RELOAD);
736 }
737
738 return ret_value;
739}
740
742 ReportList *reports,
743 Volume *volume,
744 enum ePF_FileStatus how)
745{
746 int ret_value = RET_ERROR;
747
748 if (volume != nullptr) {
749 char *new_file_path = BKE_packedfile_unpack(
750 bmain, reports, (ID *)volume, volume->filepath, volume->packedfile, how);
751 if (new_file_path != nullptr) {
752 STRNCPY(volume->filepath, new_file_path);
753 MEM_freeN(new_file_path);
754
755 BKE_packedfile_free(volume->packedfile);
756 volume->packedfile = nullptr;
757
758 BKE_volume_unload(volume);
759
760 ret_value = RET_OK;
761 }
762 }
763
764 return ret_value;
765}
766
768{
769 Library *lib;
770 char *newname;
771 int ret_value = RET_ERROR;
772
773 for (lib = static_cast<Library *>(bmain->libraries.first); lib;
774 lib = static_cast<Library *>(lib->id.next))
775 {
776 if (lib->packedfile && lib->filepath[0]) {
777
778 newname = BKE_packedfile_unpack_to_file(reports,
780 lib->runtime.filepath_abs,
781 lib->runtime.filepath_abs,
782 lib->packedfile,
784 if (newname != nullptr) {
785 ret_value = RET_OK;
786
787 printf("Unpacked .blend library: %s\n", newname);
788
789 BKE_packedfile_free(lib->packedfile);
790 lib->packedfile = nullptr;
791
792 MEM_freeN(newname);
793 }
794 }
795 }
796
797 return ret_value;
798}
799
801{
802 Library *lib;
803
804 /* Test for relativeness. */
805 for (lib = static_cast<Library *>(bmain->libraries.first); lib;
806 lib = static_cast<Library *>(lib->id.next))
807 {
808 if (!BLI_path_is_rel(lib->filepath)) {
809 break;
810 }
811 }
812
813 if (lib) {
814 BKE_reportf(reports, RPT_ERROR, "Cannot pack absolute file: '%s'", lib->filepath);
815 return;
816 }
817
818 for (lib = static_cast<Library *>(bmain->libraries.first); lib;
819 lib = static_cast<Library *>(lib->id.next))
820 {
821 if (lib->packedfile == nullptr) {
822 lib->packedfile = BKE_packedfile_new(reports, lib->filepath, BKE_main_blendfile_path(bmain));
823 }
824 }
825}
826
828{
829 Image *ima;
830 VFont *vf;
831 bSound *sound;
832 Volume *volume;
833
834 for (ima = static_cast<Image *>(bmain->images.first); ima;
835 ima = static_cast<Image *>(ima->id.next))
836 {
837 if (BKE_image_has_packedfile(ima) && !ID_IS_LINKED(ima)) {
838 BKE_packedfile_unpack_image(bmain, reports, ima, how);
839 }
840 }
841
842 for (vf = static_cast<VFont *>(bmain->fonts.first); vf; vf = static_cast<VFont *>(vf->id.next)) {
843 if (vf->packedfile && !ID_IS_LINKED(vf)) {
844 BKE_packedfile_unpack_vfont(bmain, reports, vf, how);
845 }
846 }
847
848 for (sound = static_cast<bSound *>(bmain->sounds.first); sound;
849 sound = static_cast<bSound *>(sound->id.next))
850 {
851 if (sound->packedfile && !ID_IS_LINKED(sound)) {
852 BKE_packedfile_unpack_sound(bmain, reports, sound, how);
853 }
854 }
855
856 for (volume = static_cast<Volume *>(bmain->volumes.first); volume;
857 volume = static_cast<Volume *>(volume->id.next))
858 {
859 if (volume->packedfile && !ID_IS_LINKED(volume)) {
860 BKE_packedfile_unpack_volume(bmain, reports, volume, how);
861 }
862 }
863
864 LISTBASE_FOREACH (Object *, object, &bmain->objects) {
865 if (ID_IS_LINKED(object)) {
866 continue;
867 }
868 LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
869 if (md->type == eModifierType_Nodes) {
870 NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
873 *bmain, reports, *object, *nmd, bake, how);
874 }
875 }
876 }
877 }
878}
879
881{
882 switch (GS(id->name)) {
883 case ID_IM: {
884 const Image *ima = (const Image *)id;
885 return BKE_image_has_packedfile(ima);
886 }
887 case ID_VF: {
888 const VFont *vf = (const VFont *)id;
889 return vf->packedfile != nullptr;
890 }
891 case ID_SO: {
892 const bSound *snd = (const bSound *)id;
893 return snd->packedfile != nullptr;
894 }
895 case ID_VO: {
896 const Volume *volume = (const Volume *)id;
897 return volume->packedfile != nullptr;
898 }
899 case ID_LI: {
900 const Library *li = (const Library *)id;
901 return li->packedfile != nullptr;
902 }
903 default:
904 break;
905 }
906 return false;
907}
908
909void BKE_packedfile_id_unpack(Main *bmain, ID *id, ReportList *reports, enum ePF_FileStatus how)
910{
911 /* Only unpack when datablock is editable. */
912 if (!ID_IS_EDITABLE(id)) {
913 return;
914 }
915
916 switch (GS(id->name)) {
917 case ID_IM: {
918 Image *ima = (Image *)id;
919 if (BKE_image_has_packedfile(ima)) {
920 BKE_packedfile_unpack_image(bmain, reports, ima, how);
921 }
922 break;
923 }
924 case ID_VF: {
925 VFont *vf = (VFont *)id;
926 if (vf->packedfile) {
927 BKE_packedfile_unpack_vfont(bmain, reports, vf, how);
928 }
929 break;
930 }
931 case ID_SO: {
932 bSound *snd = (bSound *)id;
933 if (snd->packedfile) {
934 BKE_packedfile_unpack_sound(bmain, reports, snd, how);
935 }
936 break;
937 }
938 case ID_VO: {
939 Volume *volume = (Volume *)id;
940 if (volume->packedfile) {
941 BKE_packedfile_unpack_volume(bmain, reports, volume, how);
942 }
943 break;
944 }
945 case ID_LI: {
946 Library *li = (Library *)id;
947 BKE_reportf(reports, RPT_ERROR, "Cannot unpack individual Library file, '%s'", li->filepath);
948 break;
949 }
950 default:
951 break;
952 }
953}
954
956{
957 if (pf == nullptr) {
958 return;
959 }
961 BLO_write_shared(writer, pf->data, pf->size, pf->sharing_info, [&]() {
962 BLO_write_raw(writer, pf->size, pf->data);
963 });
964}
965
967{
968 BLO_read_struct(reader, PackedFile, pf_p);
969 PackedFile *pf = *pf_p;
970 if (pf == nullptr) {
971 return;
972 }
973 /* NOTE: there is no way to handle endianness switch here. */
974 pf->sharing_info = BLO_read_shared(reader, &pf->data, [&]() {
975 BLO_read_data_address(reader, &pf->data);
976 /* Do not create an implicit sharing if read data pointer is `nullptr`. */
977 return pf->data ? blender::implicit_sharing::info_for_mem_free(const_cast<void *>(pf->data)) :
978 nullptr;
979 });
980 if (pf->data == nullptr) {
981 /* We cannot allow a #PackedFile with a nullptr data field,
982 * the whole code assumes this is not possible. See #70315. */
983 CLOG_WARN(&LOG,
984 "%s: nullptr packedfile data (source: '%s'), cleaning up...",
985 __func__,
986 filepath.c_str());
987 BLI_assert(pf->sharing_info == nullptr);
988 MEM_SAFE_FREE(*pf_p);
989 }
990}
void BKE_image_packfiles(ReportList *reports, Image *ima, const char *basepath)
void BKE_image_ensure_tile_token(char *filepath, size_t filepath_maxncpy)
#define IMA_SIGNAL_RELOAD
Definition BKE_image.hh:137
bool BKE_image_has_packedfile(const Image *image)
void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal)
char BKE_ftype_to_imtype(int ftype, const ImbFormatOptions *options)
int BKE_image_path_ext_from_imtype_ensure(char *filepath, size_t filepath_maxncpy, char imtype)
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:832
ePF_FileCompare
@ PF_CMP_EQUAL
@ PF_CMP_NOFILE
@ PF_CMP_DIFFERS
#define RET_OK
#define RET_ERROR
ePF_FileStatus
@ PF_USE_ORIGINAL
@ PF_USE_LOCAL
@ PF_KEEP
@ PF_REMOVE
@ PF_WRITE_ORIGINAL
@ PF_WRITE_LOCAL
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
void BKE_sound_load(struct Main *bmain, struct bSound *sound)
bool BKE_vfont_is_builtin(const VFont *vfont)
Definition vfont.cc:232
Volume data-block.
void BKE_volume_unload(Volume *volume)
#define BLI_assert(a)
Definition BLI_assert.h:50
#define ATTR_FALLTHROUGH
int BLI_exists(const char *path) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition storage.cc:350
int BLI_copy(const char *path_src, const char *path_dst) ATTR_NONNULL()
#define O_BINARY
int BLI_stat(const char *path, BLI_stat_t *buffer) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
size_t BLI_file_descriptor_size(int file) ATTR_WARN_UNUSED_RESULT
Definition storage.cc:206
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:505
int BLI_open(const char *filepath, int oflag, int pmode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
int64_t BLI_read(int fd, void *buf, size_t nbytes)
Definition fileops_c.cc:96
bool BLI_file_ensure_parent_dir_exists(const char *filepath) ATTR_NONNULL(1)
Definition fileops_c.cc:429
void * BLI_findstring(const struct ListBase *listbase, const char *id, int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define LISTBASE_FOREACH(type, var, list)
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
#define FILE_MAX
#define BLI_path_join(...)
void BLI_path_split_dir_file(const char *filepath, char *dir, size_t dir_maxncpy, char *file, size_t file_maxncpy) ATTR_NONNULL(1
bool BLI_path_is_rel(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
bool BLI_path_make_safe_filename(char *filename) ATTR_NONNULL(1)
#define FILE_MAXDIR
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define STRNCPY_RLEN(dst, src)
Definition BLI_string.h:596
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
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
char * BLI_strncpy(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
unsigned char uchar
#define ELEM(...)
#define BLO_write_struct(writer, struct_name, data_ptr)
#define BLO_read_struct(reader, struct_name, ptr_p)
void BLO_write_shared(BlendWriter *writer, const void *data, size_t approximate_size_in_bytes, const blender::ImplicitSharingInfo *sharing_info, blender::FunctionRef< void()> write_fn)
const blender::ImplicitSharingInfo * BLO_read_shared(BlendDataReader *reader, T **data_ptr, blender::FunctionRef< const blender::ImplicitSharingInfo *()> read_fn)
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
ID and Library types, which are fundamental for SDNA.
#define ID_IS_LINKED(_id)
Definition DNA_ID.h:654
#define ID_BLEND_PATH(_bmain, _id)
Definition DNA_ID.h:647
#define ID_IS_EDITABLE(_id)
Definition DNA_ID.h:658
@ ID_LI
@ ID_IM
@ ID_VO
@ ID_SO
@ ID_VF
@ IMA_SRC_FILE
@ IMA_SRC_MOVIE
@ IMA_SRC_TILED
@ IMA_SRC_SEQUENCE
@ eModifierType_Nodes
int IMB_ispic_type_from_memory(const unsigned char *buf, size_t buf_size)
eImbFileType
@ IMB_FTYPE_NONE
Contains defines and structs used throughout the imbuf module.
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static int verbose
Definition cineonlib.cc:31
constexpr const char * c_str() const
#define printf
FILE * file
#define offsetof(t, d)
int len
#define pf(_x, _i)
Prefetch 64.
Definition gim_memory.h:48
int count
#define GS(x)
Definition iris.cc:202
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
void *(* MEM_dupallocN)(const void *vmemh)
Definition mallocn.cc:39
UnpackGeometryNodesBakeResult unpack_geometry_nodes_bake(Main &bmain, ReportList *reports, Object &object, NodesModifierData &nmd, NodesModifierBake &bake, ePF_FileStatus how)
PackGeometryNodesBakeResult pack_geometry_nodes_bake(Main &bmain, ReportList *reports, Object &object, NodesModifierData &nmd, NodesModifierBake &bake)
const ImplicitSharingInfo * info_for_mem_free(void *data)
int BKE_packedfile_unpack_all_libraries(Main *bmain, ReportList *reports)
PackedFile * BKE_packedfile_duplicate(const PackedFile *pf_src)
void BKE_packedfile_free(PackedFile *pf)
PackedFileCount BKE_packedfile_count_all(Main *bmain)
PackedFile * BKE_packedfile_new_from_memory(const void *mem, int memlen, const blender::ImplicitSharingInfo *sharing_info)
void BKE_packedfile_blend_read(BlendDataReader *reader, PackedFile **pf_p, StringRefNull filepath)
bool BKE_packedfile_id_check(const ID *id)
int BKE_packedfile_unpack_sound(Main *bmain, ReportList *reports, bSound *sound, enum ePF_FileStatus how)
void BKE_packedfile_unpack_all(Main *bmain, ReportList *reports, enum ePF_FileStatus how)
void BKE_packedfile_pack_all_libraries(Main *bmain, ReportList *reports)
int BKE_packedfile_read(PackedFile *pf, void *data, int size)
Definition packedFile.cc:95
int BKE_packedfile_unpack_image(Main *bmain, ReportList *reports, Image *ima, enum ePF_FileStatus how)
char * BKE_packedfile_unpack_to_file(ReportList *reports, const char *ref_file_name, const char *abs_name, const char *local_name, PackedFile *pf, enum ePF_FileStatus how)
int BKE_packedfile_unpack_vfont(Main *bmain, ReportList *reports, VFont *vfont, enum ePF_FileStatus how)
void BKE_packedfile_blend_write(BlendWriter *writer, const PackedFile *pf)
char * BKE_packedfile_unpack(Main *bmain, ReportList *reports, ID *id, const char *orig_file_path, PackedFile *pf, enum ePF_FileStatus how)
void BKE_packedfile_rewind(PackedFile *pf)
Definition packedFile.cc:90
int BKE_packedfile_seek(PackedFile *pf, int offset, int whence)
Definition packedFile.cc:58
PackedFile * BKE_packedfile_new(ReportList *reports, const char *filepath_rel, const char *basepath)
static void unpack_generate_paths(const char *filepath, ID *id, char *r_abspath, size_t abspath_maxncpy, char *r_relpath, size_t relpath_maxncpy)
static CLG_LogRef LOG
Definition packedFile.cc:54
int BKE_packedfile_write_to_file(ReportList *reports, const char *ref_file_name, const char *filepath_rel, PackedFile *pf)
int BKE_packedfile_unpack_volume(Main *bmain, ReportList *reports, Volume *volume, enum ePF_FileStatus how)
enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name, const char *filepath_rel, const PackedFile *pf)
void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose)
void BKE_packedfile_id_unpack(Main *bmain, ID *id, ReportList *reports, enum ePF_FileStatus how)
Definition DNA_ID.h:413
void * next
Definition DNA_ID.h:416
char name[66]
Definition DNA_ID.h:425
struct PackedFile * packedfile
char filepath[1024]
char filepath[1024]
struct ListBase packedfiles
short source
struct PackedFile * packedfile
Definition DNA_ID.h:533
char filepath[1024]
Definition DNA_ID.h:531
void * last
void * first
ListBase volumes
Definition BKE_main.hh:253
ListBase fonts
Definition BKE_main.hh:226
ListBase sounds
Definition BKE_main.hh:230
ListBase libraries
Definition BKE_main.hh:211
ListBase images
Definition BKE_main.hh:218
ListBase objects
Definition BKE_main.hh:212
NodesModifierBake * bakes
const void * data
const ImplicitSharingInfoHandle * sharing_info
char filepath[1024]
struct PackedFile * packedfile
struct PackedFile * packedfile
struct PackedFile * packedfile
char filepath[1024]
static DynamicLibrary lib