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