1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup bke
22 */
23
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <sys/stat.h>
27
28 #ifndef WIN32
29 # include <unistd.h>
30 #else
31 # include <io.h>
32 #endif
33 #include "MEM_guardedalloc.h"
34 #include <string.h>
35
36 #include "DNA_ID.h"
37 #include "DNA_image_types.h"
38 #include "DNA_packedFile_types.h"
39 #include "DNA_sound_types.h"
40 #include "DNA_vfont_types.h"
41 #include "DNA_volume_types.h"
42
43 #include "BLI_blenlib.h"
44 #include "BLI_utildefines.h"
45
46 #include "BKE_font.h"
47 #include "BKE_image.h"
48 #include "BKE_main.h"
49 #include "BKE_packedFile.h"
50 #include "BKE_report.h"
51 #include "BKE_sound.h"
52 #include "BKE_volume.h"
53
54 #include "BLO_read_write.h"
55
BKE_packedfile_seek(PackedFile * pf,int offset,int whence)56 int BKE_packedfile_seek(PackedFile *pf, int offset, int whence)
57 {
58 int oldseek = -1, seek = 0;
59
60 if (pf) {
61 oldseek = pf->seek;
62 switch (whence) {
63 case SEEK_CUR:
64 seek = oldseek + offset;
65 break;
66 case SEEK_END:
67 seek = pf->size + offset;
68 break;
69 case SEEK_SET:
70 seek = offset;
71 break;
72 default:
73 oldseek = -1;
74 break;
75 }
76 if (seek < 0) {
77 seek = 0;
78 }
79 else if (seek > pf->size) {
80 seek = pf->size;
81 }
82 pf->seek = seek;
83 }
84
85 return oldseek;
86 }
87
BKE_packedfile_rewind(PackedFile * pf)88 void BKE_packedfile_rewind(PackedFile *pf)
89 {
90 BKE_packedfile_seek(pf, 0, SEEK_SET);
91 }
92
BKE_packedfile_read(PackedFile * pf,void * data,int size)93 int BKE_packedfile_read(PackedFile *pf, void *data, int size)
94 {
95 if ((pf != NULL) && (size >= 0) && (data != NULL)) {
96 if (size + pf->seek > pf->size) {
97 size = pf->size - pf->seek;
98 }
99
100 if (size > 0) {
101 memcpy(data, ((char *)pf->data) + pf->seek, size);
102 }
103 else {
104 size = 0;
105 }
106
107 pf->seek += size;
108 }
109 else {
110 size = -1;
111 }
112
113 return size;
114 }
115
BKE_packedfile_count_all(Main * bmain)116 int BKE_packedfile_count_all(Main *bmain)
117 {
118 Image *ima;
119 VFont *vf;
120 bSound *sound;
121 Volume *volume;
122 int count = 0;
123
124 /* let's check if there are packed files... */
125 for (ima = bmain->images.first; ima; ima = ima->id.next) {
126 if (BKE_image_has_packedfile(ima)) {
127 count++;
128 }
129 }
130
131 for (vf = bmain->fonts.first; vf; vf = vf->id.next) {
132 if (vf->packedfile) {
133 count++;
134 }
135 }
136
137 for (sound = bmain->sounds.first; sound; sound = sound->id.next) {
138 if (sound->packedfile) {
139 count++;
140 }
141 }
142
143 for (volume = bmain->volumes.first; volume; volume = volume->id.next) {
144 if (volume->packedfile) {
145 count++;
146 }
147 }
148
149 return count;
150 }
151
BKE_packedfile_free(PackedFile * pf)152 void BKE_packedfile_free(PackedFile *pf)
153 {
154 if (pf) {
155 BLI_assert(pf->data != NULL);
156
157 MEM_SAFE_FREE(pf->data);
158 MEM_freeN(pf);
159 }
160 else {
161 printf("%s: Trying to free a NULL pointer\n", __func__);
162 }
163 }
164
BKE_packedfile_duplicate(const PackedFile * pf_src)165 PackedFile *BKE_packedfile_duplicate(const PackedFile *pf_src)
166 {
167 BLI_assert(pf_src != NULL);
168 BLI_assert(pf_src->data != NULL);
169
170 PackedFile *pf_dst;
171
172 pf_dst = MEM_dupallocN(pf_src);
173 pf_dst->data = MEM_dupallocN(pf_src->data);
174
175 return pf_dst;
176 }
177
BKE_packedfile_new_from_memory(void * mem,int memlen)178 PackedFile *BKE_packedfile_new_from_memory(void *mem, int memlen)
179 {
180 BLI_assert(mem != NULL);
181
182 PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
183 pf->data = mem;
184 pf->size = memlen;
185
186 return pf;
187 }
188
BKE_packedfile_new(ReportList * reports,const char * filename,const char * basepath)189 PackedFile *BKE_packedfile_new(ReportList *reports, const char *filename, const char *basepath)
190 {
191 PackedFile *pf = NULL;
192 int file, filelen;
193 char name[FILE_MAX];
194 void *data;
195
196 /* render result has no filename and can be ignored
197 * any other files with no name can be ignored too */
198 if (filename[0] == '\0') {
199 return pf;
200 }
201
202 // XXX waitcursor(1);
203
204 /* convert relative filenames to absolute filenames */
205
206 BLI_strncpy(name, filename, sizeof(name));
207 BLI_path_abs(name, basepath);
208
209 /* open the file
210 * and create a PackedFile structure */
211
212 file = BLI_open(name, O_BINARY | O_RDONLY, 0);
213 if (file == -1) {
214 BKE_reportf(reports, RPT_ERROR, "Unable to pack file, source path '%s' not found", name);
215 }
216 else {
217 filelen = BLI_file_descriptor_size(file);
218
219 if (filelen == 0) {
220 /* MEM_mallocN complains about MEM_mallocN(0, "bla");
221 * we don't care.... */
222 data = MEM_mallocN(1, "packFile");
223 }
224 else {
225 data = MEM_mallocN(filelen, "packFile");
226 }
227 if (read(file, data, filelen) == filelen) {
228 pf = BKE_packedfile_new_from_memory(data, filelen);
229 }
230 else {
231 MEM_freeN(data);
232 }
233
234 close(file);
235 }
236
237 // XXX waitcursor(0);
238
239 return pf;
240 }
241
242 /* no libraries for now */
BKE_packedfile_pack_all(Main * bmain,ReportList * reports,bool verbose)243 void BKE_packedfile_pack_all(Main *bmain, ReportList *reports, bool verbose)
244 {
245 Image *ima;
246 VFont *vfont;
247 bSound *sound;
248 Volume *volume;
249 int tot = 0;
250
251 for (ima = bmain->images.first; ima; ima = ima->id.next) {
252 if (BKE_image_has_packedfile(ima) == false && !ID_IS_LINKED(ima)) {
253 if (ima->source == IMA_SRC_FILE) {
254 BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
255 tot++;
256 }
257 else if (BKE_image_has_multiple_ibufs(ima) && verbose) {
258 BKE_reportf(reports,
259 RPT_WARNING,
260 "Image '%s' skipped, movies, image sequences and packed files not supported",
261 ima->id.name + 2);
262 }
263 }
264 }
265
266 for (vfont = bmain->fonts.first; vfont; vfont = vfont->id.next) {
267 if (vfont->packedfile == NULL && !ID_IS_LINKED(vfont) &&
268 BKE_vfont_is_builtin(vfont) == false) {
269 vfont->packedfile = BKE_packedfile_new(
270 reports, vfont->filepath, BKE_main_blendfile_path(bmain));
271 tot++;
272 }
273 }
274
275 for (sound = bmain->sounds.first; sound; sound = sound->id.next) {
276 if (sound->packedfile == NULL && !ID_IS_LINKED(sound)) {
277 sound->packedfile = BKE_packedfile_new(
278 reports, sound->filepath, BKE_main_blendfile_path(bmain));
279 tot++;
280 }
281 }
282
283 for (volume = bmain->volumes.first; volume; volume = volume->id.next) {
284 if (volume->packedfile == NULL && !ID_IS_LINKED(volume)) {
285 volume->packedfile = BKE_packedfile_new(
286 reports, volume->filepath, BKE_main_blendfile_path(bmain));
287 tot++;
288 }
289 }
290
291 if (tot > 0) {
292 BKE_reportf(reports, RPT_INFO, "Packed %d file(s)", tot);
293 }
294 else if (verbose) {
295 BKE_report(reports, RPT_INFO, "No new files have been packed");
296 }
297 }
298
BKE_packedfile_write_to_file(ReportList * reports,const char * ref_file_name,const char * filename,PackedFile * pf,const bool guimode)299 int BKE_packedfile_write_to_file(ReportList *reports,
300 const char *ref_file_name,
301 const char *filename,
302 PackedFile *pf,
303 const bool guimode)
304 {
305 int file, number;
306 int ret_value = RET_OK;
307 bool remove_tmp = false;
308 char name[FILE_MAX];
309 char tempname[FILE_MAX];
310 /* void *data; */
311
312 if (guimode) {
313 } // XXX waitcursor(1);
314
315 BLI_strncpy(name, filename, sizeof(name));
316 BLI_path_abs(name, ref_file_name);
317
318 if (BLI_exists(name)) {
319 for (number = 1; number <= 999; number++) {
320 BLI_snprintf(tempname, sizeof(tempname), "%s.%03d_", name, number);
321 if (!BLI_exists(tempname)) {
322 if (BLI_copy(name, tempname) == RET_OK) {
323 remove_tmp = true;
324 }
325 break;
326 }
327 }
328 }
329
330 /* make sure the path to the file exists... */
331 BLI_make_existing_file(name);
332
333 file = BLI_open(name, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666);
334 if (file == -1) {
335 BKE_reportf(reports, RPT_ERROR, "Error creating file '%s'", name);
336 ret_value = RET_ERROR;
337 }
338 else {
339 if (write(file, pf->data, pf->size) != pf->size) {
340 BKE_reportf(reports, RPT_ERROR, "Error writing file '%s'", name);
341 ret_value = RET_ERROR;
342 }
343 else {
344 BKE_reportf(reports, RPT_INFO, "Saved packed file to: %s", name);
345 }
346
347 close(file);
348 }
349
350 if (remove_tmp) {
351 if (ret_value == RET_ERROR) {
352 if (BLI_rename(tempname, name) != 0) {
353 BKE_reportf(reports,
354 RPT_ERROR,
355 "Error restoring temp file (check files '%s' '%s')",
356 tempname,
357 name);
358 }
359 }
360 else {
361 if (BLI_delete(tempname, false, false) != 0) {
362 BKE_reportf(reports, RPT_ERROR, "Error deleting '%s' (ignored)", tempname);
363 }
364 }
365 }
366
367 if (guimode) {
368 } // XXX waitcursor(0);
369
370 return ret_value;
371 }
372
373 /**
374 * This function compares a packed file to a 'real' file.
375 * It returns an integer indicating if:
376 *
377 * - PF_EQUAL: the packed file and original file are identical
378 * - PF_DIFFERENT: the packed file and original file differ
379 * - PF_NOFILE: the original file doesn't exist
380 */
BKE_packedfile_compare_to_file(const char * ref_file_name,const char * filename,PackedFile * pf)381 enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name,
382 const char *filename,
383 PackedFile *pf)
384 {
385 BLI_stat_t st;
386 enum ePF_FileCompare ret_val;
387 char buf[4096];
388 char name[FILE_MAX];
389
390 BLI_strncpy(name, filename, sizeof(name));
391 BLI_path_abs(name, ref_file_name);
392
393 if (BLI_stat(name, &st) == -1) {
394 ret_val = PF_CMP_NOFILE;
395 }
396 else if (st.st_size != pf->size) {
397 ret_val = PF_CMP_DIFFERS;
398 }
399 else {
400 /* we'll have to compare the two... */
401
402 const int file = BLI_open(name, O_BINARY | O_RDONLY, 0);
403 if (file == -1) {
404 ret_val = PF_CMP_NOFILE;
405 }
406 else {
407 ret_val = PF_CMP_EQUAL;
408
409 for (int i = 0; i < pf->size; i += sizeof(buf)) {
410 int len = pf->size - i;
411 if (len > sizeof(buf)) {
412 len = sizeof(buf);
413 }
414
415 if (read(file, buf, len) != len) {
416 /* read error ... */
417 ret_val = PF_CMP_DIFFERS;
418 break;
419 }
420
421 if (memcmp(buf, ((char *)pf->data) + i, len) != 0) {
422 ret_val = PF_CMP_DIFFERS;
423 break;
424 }
425 }
426
427 close(file);
428 }
429 }
430
431 return ret_val;
432 }
433
434 /**
435 * #BKE_packedfile_unpack_to_file() looks at the existing files (abs_name, local_name)
436 * and a packed file.
437 *
438 * It returns a char *to the existing file name / new file name or NULL when
439 * there was an error or when the user decides to cancel the operation.
440 *
441 * \warning 'abs_name' may be relative still! (use a "//" prefix)
442 * be sure to run #BLI_path_abs on it first.
443 */
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)444 char *BKE_packedfile_unpack_to_file(ReportList *reports,
445 const char *ref_file_name,
446 const char *abs_name,
447 const char *local_name,
448 PackedFile *pf,
449 enum ePF_FileStatus how)
450 {
451 char *newname = NULL;
452 const char *temp = NULL;
453
454 if (pf != NULL) {
455 switch (how) {
456 case PF_KEEP:
457 break;
458 case PF_REMOVE:
459 temp = abs_name;
460 break;
461 case PF_USE_LOCAL: {
462 char temp_abs[FILE_MAX];
463
464 BLI_strncpy(temp_abs, local_name, sizeof(temp_abs));
465 BLI_path_abs(temp_abs, ref_file_name);
466
467 /* if file exists use it */
468 if (BLI_exists(temp_abs)) {
469 temp = local_name;
470 break;
471 }
472 /* else create it */
473 ATTR_FALLTHROUGH;
474 }
475 case PF_WRITE_LOCAL:
476 if (BKE_packedfile_write_to_file(reports, ref_file_name, local_name, pf, 1) == RET_OK) {
477 temp = local_name;
478 }
479 break;
480 case PF_USE_ORIGINAL: {
481 char temp_abs[FILE_MAX];
482
483 BLI_strncpy(temp_abs, abs_name, sizeof(temp_abs));
484 BLI_path_abs(temp_abs, ref_file_name);
485
486 /* if file exists use it */
487 if (BLI_exists(temp_abs)) {
488 BKE_reportf(reports, RPT_INFO, "Use existing file (instead of packed): %s", abs_name);
489 temp = abs_name;
490 break;
491 }
492 /* else create it */
493 ATTR_FALLTHROUGH;
494 }
495 case PF_WRITE_ORIGINAL:
496 if (BKE_packedfile_write_to_file(reports, ref_file_name, abs_name, pf, 1) == RET_OK) {
497 temp = abs_name;
498 }
499 break;
500 default:
501 printf("%s: unknown return_value %u\n", __func__, how);
502 break;
503 }
504
505 if (temp) {
506 newname = BLI_strdup(temp);
507 }
508 }
509
510 return newname;
511 }
512
unpack_generate_paths(const char * name,ID * id,char * r_abspath,char * r_relpath,size_t abspathlen,size_t relpathlen)513 static void unpack_generate_paths(const char *name,
514 ID *id,
515 char *r_abspath,
516 char *r_relpath,
517 size_t abspathlen,
518 size_t relpathlen)
519 {
520 char tempname[FILE_MAX];
521 char tempdir[FILE_MAXDIR];
522
523 BLI_split_dirfile(name, tempdir, tempname, sizeof(tempdir), sizeof(tempname));
524
525 if (tempname[0] == '\0') {
526 /* Note: we do not have any real way to re-create extension out of data... */
527 BLI_strncpy(tempname, id->name + 2, sizeof(tempname));
528 printf("%s\n", tempname);
529 BLI_filename_make_safe(tempname);
530 printf("%s\n", tempname);
531 }
532
533 if (tempdir[0] == '\0') {
534 /* Fallback to relative dir. */
535 BLI_strncpy(tempdir, "//", sizeof(tempdir));
536 }
537
538 switch (GS(id->name)) {
539 case ID_VF:
540 BLI_snprintf(r_relpath, relpathlen, "//fonts/%s", tempname);
541 break;
542 case ID_SO:
543 BLI_snprintf(r_relpath, relpathlen, "//sounds/%s", tempname);
544 break;
545 case ID_IM:
546 BLI_snprintf(r_relpath, relpathlen, "//textures/%s", tempname);
547 break;
548 case ID_VO:
549 BLI_snprintf(r_relpath, relpathlen, "//volumes/%s", tempname);
550 break;
551 default:
552 break;
553 }
554
555 {
556 size_t len = BLI_strncpy_rlen(r_abspath, tempdir, abspathlen);
557 BLI_strncpy(r_abspath + len, tempname, abspathlen - len);
558 }
559 }
560
BKE_packedfile_unpack_vfont(Main * bmain,ReportList * reports,VFont * vfont,enum ePF_FileStatus how)561 int BKE_packedfile_unpack_vfont(Main *bmain,
562 ReportList *reports,
563 VFont *vfont,
564 enum ePF_FileStatus how)
565 {
566 char localname[FILE_MAX], absname[FILE_MAX];
567 char *newname;
568 int ret_value = RET_ERROR;
569
570 if (vfont != NULL) {
571 unpack_generate_paths(
572 vfont->filepath, (ID *)vfont, absname, localname, sizeof(absname), sizeof(localname));
573 newname = BKE_packedfile_unpack_to_file(
574 reports, BKE_main_blendfile_path(bmain), absname, localname, vfont->packedfile, how);
575 if (newname != NULL) {
576 ret_value = RET_OK;
577 BKE_packedfile_free(vfont->packedfile);
578 vfont->packedfile = NULL;
579 BLI_strncpy(vfont->filepath, newname, sizeof(vfont->filepath));
580 MEM_freeN(newname);
581 }
582 }
583
584 return ret_value;
585 }
586
BKE_packedfile_unpack_sound(Main * bmain,ReportList * reports,bSound * sound,enum ePF_FileStatus how)587 int BKE_packedfile_unpack_sound(Main *bmain,
588 ReportList *reports,
589 bSound *sound,
590 enum ePF_FileStatus how)
591 {
592 char localname[FILE_MAX], absname[FILE_MAX];
593 char *newname;
594 int ret_value = RET_ERROR;
595
596 if (sound != NULL) {
597 unpack_generate_paths(
598 sound->filepath, (ID *)sound, absname, localname, sizeof(absname), sizeof(localname));
599 newname = BKE_packedfile_unpack_to_file(
600 reports, BKE_main_blendfile_path(bmain), absname, localname, sound->packedfile, how);
601 if (newname != NULL) {
602 BLI_strncpy(sound->filepath, newname, sizeof(sound->filepath));
603 MEM_freeN(newname);
604
605 BKE_packedfile_free(sound->packedfile);
606 sound->packedfile = NULL;
607
608 BKE_sound_load(bmain, sound);
609
610 ret_value = RET_OK;
611 }
612 }
613
614 return ret_value;
615 }
616
BKE_packedfile_unpack_image(Main * bmain,ReportList * reports,Image * ima,enum ePF_FileStatus how)617 int BKE_packedfile_unpack_image(Main *bmain,
618 ReportList *reports,
619 Image *ima,
620 enum ePF_FileStatus how)
621 {
622 int ret_value = RET_ERROR;
623
624 if (ima != NULL) {
625 while (ima->packedfiles.last) {
626 char localname[FILE_MAX], absname[FILE_MAX];
627 char *newname;
628 ImagePackedFile *imapf = ima->packedfiles.last;
629
630 unpack_generate_paths(
631 imapf->filepath, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname));
632 newname = BKE_packedfile_unpack_to_file(
633 reports, BKE_main_blendfile_path(bmain), absname, localname, imapf->packedfile, how);
634
635 if (newname != NULL) {
636 ImageView *iv;
637
638 ret_value = ret_value == RET_ERROR ? RET_ERROR : RET_OK;
639 BKE_packedfile_free(imapf->packedfile);
640 imapf->packedfile = NULL;
641
642 /* update the new corresponding view filepath */
643 iv = BLI_findstring(&ima->views, imapf->filepath, offsetof(ImageView, filepath));
644 if (iv) {
645 BLI_strncpy(iv->filepath, newname, sizeof(imapf->filepath));
646 }
647
648 /* keep the new name in the image for non-pack specific reasons */
649 if (how != PF_REMOVE) {
650 BLI_strncpy(ima->filepath, newname, sizeof(imapf->filepath));
651 }
652 MEM_freeN(newname);
653 }
654 else {
655 ret_value = RET_ERROR;
656 }
657
658 BLI_remlink(&ima->packedfiles, imapf);
659 MEM_freeN(imapf);
660 }
661 }
662
663 if (ret_value == RET_OK) {
664 BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_RELOAD);
665 }
666
667 return ret_value;
668 }
669
BKE_packedfile_unpack_volume(Main * bmain,ReportList * reports,Volume * volume,enum ePF_FileStatus how)670 int BKE_packedfile_unpack_volume(Main *bmain,
671 ReportList *reports,
672 Volume *volume,
673 enum ePF_FileStatus how)
674 {
675 char localname[FILE_MAX], absname[FILE_MAX];
676 char *newfilepath;
677 int ret_value = RET_ERROR;
678
679 if (volume != NULL) {
680 unpack_generate_paths(
681 volume->filepath, (ID *)volume, absname, localname, sizeof(absname), sizeof(localname));
682 newfilepath = BKE_packedfile_unpack_to_file(
683 reports, BKE_main_blendfile_path(bmain), absname, localname, volume->packedfile, how);
684 if (newfilepath != NULL) {
685 BLI_strncpy(volume->filepath, newfilepath, sizeof(volume->filepath));
686 MEM_freeN(newfilepath);
687
688 BKE_packedfile_free(volume->packedfile);
689 volume->packedfile = NULL;
690
691 BKE_volume_unload(volume);
692
693 ret_value = RET_OK;
694 }
695 }
696
697 return ret_value;
698 }
699
BKE_packedfile_unpack_all_libraries(Main * bmain,ReportList * reports)700 int BKE_packedfile_unpack_all_libraries(Main *bmain, ReportList *reports)
701 {
702 Library *lib;
703 char *newname;
704 int ret_value = RET_ERROR;
705
706 for (lib = bmain->libraries.first; lib; lib = lib->id.next) {
707 if (lib->packedfile && lib->filepath[0]) {
708
709 newname = BKE_packedfile_unpack_to_file(reports,
710 BKE_main_blendfile_path(bmain),
711 lib->filepath_abs,
712 lib->filepath_abs,
713 lib->packedfile,
714 PF_WRITE_ORIGINAL);
715 if (newname != NULL) {
716 ret_value = RET_OK;
717
718 printf("Unpacked .blend library: %s\n", newname);
719
720 BKE_packedfile_free(lib->packedfile);
721 lib->packedfile = NULL;
722
723 MEM_freeN(newname);
724 }
725 }
726 }
727
728 return ret_value;
729 }
730
BKE_packedfile_pack_all_libraries(Main * bmain,ReportList * reports)731 void BKE_packedfile_pack_all_libraries(Main *bmain, ReportList *reports)
732 {
733 Library *lib;
734
735 /* test for relativenss */
736 for (lib = bmain->libraries.first; lib; lib = lib->id.next) {
737 if (!BLI_path_is_rel(lib->filepath)) {
738 break;
739 }
740 }
741
742 if (lib) {
743 BKE_reportf(reports, RPT_ERROR, "Cannot pack absolute file: '%s'", lib->filepath);
744 return;
745 }
746
747 for (lib = bmain->libraries.first; lib; lib = lib->id.next) {
748 if (lib->packedfile == NULL) {
749 lib->packedfile = BKE_packedfile_new(reports, lib->filepath, BKE_main_blendfile_path(bmain));
750 }
751 }
752 }
753
BKE_packedfile_unpack_all(Main * bmain,ReportList * reports,enum ePF_FileStatus how)754 void BKE_packedfile_unpack_all(Main *bmain, ReportList *reports, enum ePF_FileStatus how)
755 {
756 Image *ima;
757 VFont *vf;
758 bSound *sound;
759 Volume *volume;
760
761 for (ima = bmain->images.first; ima; ima = ima->id.next) {
762 if (BKE_image_has_packedfile(ima)) {
763 BKE_packedfile_unpack_image(bmain, reports, ima, how);
764 }
765 }
766
767 for (vf = bmain->fonts.first; vf; vf = vf->id.next) {
768 if (vf->packedfile) {
769 BKE_packedfile_unpack_vfont(bmain, reports, vf, how);
770 }
771 }
772
773 for (sound = bmain->sounds.first; sound; sound = sound->id.next) {
774 if (sound->packedfile) {
775 BKE_packedfile_unpack_sound(bmain, reports, sound, how);
776 }
777 }
778
779 for (volume = bmain->volumes.first; volume; volume = volume->id.next) {
780 if (volume->packedfile) {
781 BKE_packedfile_unpack_volume(bmain, reports, volume, how);
782 }
783 }
784 }
785
786 /* ID should be not NULL, return 1 if there's a packed file */
BKE_packedfile_id_check(ID * id)787 bool BKE_packedfile_id_check(ID *id)
788 {
789 switch (GS(id->name)) {
790 case ID_IM: {
791 Image *ima = (Image *)id;
792 return BKE_image_has_packedfile(ima);
793 }
794 case ID_VF: {
795 VFont *vf = (VFont *)id;
796 return vf->packedfile != NULL;
797 }
798 case ID_SO: {
799 bSound *snd = (bSound *)id;
800 return snd->packedfile != NULL;
801 }
802 case ID_VO: {
803 Volume *volume = (Volume *)id;
804 return volume->packedfile != NULL;
805 }
806 case ID_LI: {
807 Library *li = (Library *)id;
808 return li->packedfile != NULL;
809 }
810 default:
811 break;
812 }
813 return false;
814 }
815
816 /* ID should be not NULL */
BKE_packedfile_id_unpack(Main * bmain,ID * id,ReportList * reports,enum ePF_FileStatus how)817 void BKE_packedfile_id_unpack(Main *bmain, ID *id, ReportList *reports, enum ePF_FileStatus how)
818 {
819 switch (GS(id->name)) {
820 case ID_IM: {
821 Image *ima = (Image *)id;
822 if (BKE_image_has_packedfile(ima)) {
823 BKE_packedfile_unpack_image(bmain, reports, ima, how);
824 }
825 break;
826 }
827 case ID_VF: {
828 VFont *vf = (VFont *)id;
829 if (vf->packedfile) {
830 BKE_packedfile_unpack_vfont(bmain, reports, vf, how);
831 }
832 break;
833 }
834 case ID_SO: {
835 bSound *snd = (bSound *)id;
836 if (snd->packedfile) {
837 BKE_packedfile_unpack_sound(bmain, reports, snd, how);
838 }
839 break;
840 }
841 case ID_VO: {
842 Volume *volume = (Volume *)id;
843 if (volume->packedfile) {
844 BKE_packedfile_unpack_volume(bmain, reports, volume, how);
845 }
846 break;
847 }
848 case ID_LI: {
849 Library *li = (Library *)id;
850 BKE_reportf(reports, RPT_ERROR, "Cannot unpack individual Library file, '%s'", li->filepath);
851 break;
852 }
853 default:
854 break;
855 }
856 }
857
BKE_packedfile_blend_write(BlendWriter * writer,PackedFile * pf)858 void BKE_packedfile_blend_write(BlendWriter *writer, PackedFile *pf)
859 {
860 if (pf == NULL) {
861 return;
862 }
863 BLO_write_struct(writer, PackedFile, pf);
864 BLO_write_raw(writer, pf->size, pf->data);
865 }
866
BKE_packedfile_blend_read(BlendDataReader * reader,PackedFile ** pf_p)867 void BKE_packedfile_blend_read(BlendDataReader *reader, PackedFile **pf_p)
868 {
869 BLO_read_packed_address(reader, pf_p);
870 PackedFile *pf = *pf_p;
871 if (pf == NULL) {
872 return;
873 }
874
875 BLO_read_packed_address(reader, &pf->data);
876 if (pf->data == NULL) {
877 /* We cannot allow a PackedFile with a NULL data field,
878 * the whole code assumes this is not possible. See T70315. */
879 printf("%s: NULL packedfile data, cleaning up...\n", __func__);
880 MEM_SAFE_FREE(pf);
881 }
882 }
883