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