476d1a3a91f1b01435db18bea81dc8e20e6d0257
[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(reports, vfont->name, BKE_main_blendfile_path(bmain));
268       tot++;
269     }
270   }
271
272   for (sound = bmain->sounds.first; sound; sound = sound->id.next) {
273     if (sound->packedfile == NULL && !ID_IS_LINKED(sound)) {
274       sound->packedfile = BKE_packedfile_new(reports, sound->name, BKE_main_blendfile_path(bmain));
275       tot++;
276     }
277   }
278
279   for (volume = bmain->volumes.first; volume; volume = volume->id.next) {
280     if (volume->packedfile == NULL && !ID_IS_LINKED(volume)) {
281       volume->packedfile = BKE_packedfile_new(
282           reports, volume->filepath, BKE_main_blendfile_path(bmain));
283       tot++;
284     }
285   }
286
287   if (tot > 0) {
288     BKE_reportf(reports, RPT_INFO, "Packed %d file(s)", tot);
289   }
290   else if (verbose) {
291     BKE_report(reports, RPT_INFO, "No new files have been packed");
292   }
293 }
294
295 int BKE_packedfile_write_to_file(ReportList *reports,
296                                  const char *ref_file_name,
297                                  const char *filename,
298                                  PackedFile *pf,
299                                  const bool guimode)
300 {
301   int file, number;
302   int ret_value = RET_OK;
303   bool remove_tmp = false;
304   char name[FILE_MAX];
305   char tempname[FILE_MAX];
306   /*      void *data; */
307
308   if (guimode) {
309   }  // XXX  waitcursor(1);
310
311   BLI_strncpy(name, filename, sizeof(name));
312   BLI_path_abs(name, ref_file_name);
313
314   if (BLI_exists(name)) {
315     for (number = 1; number <= 999; number++) {
316       BLI_snprintf(tempname, sizeof(tempname), "%s.%03d_", name, number);
317       if (!BLI_exists(tempname)) {
318         if (BLI_copy(name, tempname) == RET_OK) {
319           remove_tmp = true;
320         }
321         break;
322       }
323     }
324   }
325
326   /* make sure the path to the file exists... */
327   BLI_make_existing_file(name);
328
329   file = BLI_open(name, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666);
330   if (file == -1) {
331     BKE_reportf(reports, RPT_ERROR, "Error creating file '%s'", name);
332     ret_value = RET_ERROR;
333   }
334   else {
335     if (write(file, pf->data, pf->size) != pf->size) {
336       BKE_reportf(reports, RPT_ERROR, "Error writing file '%s'", name);
337       ret_value = RET_ERROR;
338     }
339     else {
340       BKE_reportf(reports, RPT_INFO, "Saved packed file to: %s", name);
341     }
342
343     close(file);
344   }
345
346   if (remove_tmp) {
347     if (ret_value == RET_ERROR) {
348       if (BLI_rename(tempname, name) != 0) {
349         BKE_reportf(reports,
350                     RPT_ERROR,
351                     "Error restoring temp file (check files '%s' '%s')",
352                     tempname,
353                     name);
354       }
355     }
356     else {
357       if (BLI_delete(tempname, false, false) != 0) {
358         BKE_reportf(reports, RPT_ERROR, "Error deleting '%s' (ignored)", tempname);
359       }
360     }
361   }
362
363   if (guimode) {
364   }  // XXX waitcursor(0);
365
366   return (ret_value);
367 }
368
369 /**
370  * This function compares a packed file to a 'real' file.
371  * It returns an integer indicating if:
372  *
373  * - PF_EQUAL:     the packed file and original file are identical
374  * - PF_DIFFERENT: the packed file and original file differ
375  * - PF_NOFILE:    the original file doesn't exist
376  */
377 enum ePF_FileCompare BKE_packedfile_compare_to_file(const char *ref_file_name,
378                                                     const char *filename,
379                                                     PackedFile *pf)
380 {
381   BLI_stat_t st;
382   enum ePF_FileCompare ret_val;
383   char buf[4096];
384   char name[FILE_MAX];
385
386   BLI_strncpy(name, filename, sizeof(name));
387   BLI_path_abs(name, ref_file_name);
388
389   if (BLI_stat(name, &st) == -1) {
390     ret_val = PF_CMP_NOFILE;
391   }
392   else if (st.st_size != pf->size) {
393     ret_val = PF_CMP_DIFFERS;
394   }
395   else {
396     /* we'll have to compare the two... */
397
398     const int file = BLI_open(name, O_BINARY | O_RDONLY, 0);
399     if (file == -1) {
400       ret_val = PF_CMP_NOFILE;
401     }
402     else {
403       ret_val = PF_CMP_EQUAL;
404
405       for (int i = 0; i < pf->size; i += sizeof(buf)) {
406         int len = pf->size - i;
407         if (len > sizeof(buf)) {
408           len = sizeof(buf);
409         }
410
411         if (read(file, buf, len) != len) {
412           /* read error ... */
413           ret_val = PF_CMP_DIFFERS;
414           break;
415         }
416         else {
417           if (memcmp(buf, ((char *)pf->data) + i, len)) {
418             ret_val = PF_CMP_DIFFERS;
419             break;
420           }
421         }
422       }
423
424       close(file);
425     }
426   }
427
428   return (ret_val);
429 }
430
431 /**
432  * #BKE_packedfile_unpack_to_file() looks at the existing files (abs_name, local_name)
433  * and a packed file.
434  *
435  * It returns a char *to the existing file name / new file name or NULL when
436  * there was an error or when the user decides to cancel the operation.
437  *
438  * \warning 'abs_name' may be relative still! (use a "//" prefix)
439  * be sure to run #BLI_path_abs on it first.
440  */
441 char *BKE_packedfile_unpack_to_file(ReportList *reports,
442                                     const char *ref_file_name,
443                                     const char *abs_name,
444                                     const char *local_name,
445                                     PackedFile *pf,
446                                     enum ePF_FileStatus how)
447 {
448   char *newname = NULL;
449   const char *temp = NULL;
450
451   if (pf != NULL) {
452     switch (how) {
453       case PF_KEEP:
454         break;
455       case PF_REMOVE:
456         temp = abs_name;
457         break;
458       case PF_USE_LOCAL: {
459         char temp_abs[FILE_MAX];
460
461         BLI_strncpy(temp_abs, local_name, sizeof(temp_abs));
462         BLI_path_abs(temp_abs, ref_file_name);
463
464         /* if file exists use it */
465         if (BLI_exists(temp_abs)) {
466           temp = local_name;
467           break;
468         }
469         /* else create it */
470         ATTR_FALLTHROUGH;
471       }
472       case PF_WRITE_LOCAL:
473         if (BKE_packedfile_write_to_file(reports, ref_file_name, local_name, pf, 1) == RET_OK) {
474           temp = local_name;
475         }
476         break;
477       case PF_USE_ORIGINAL: {
478         char temp_abs[FILE_MAX];
479
480         BLI_strncpy(temp_abs, abs_name, sizeof(temp_abs));
481         BLI_path_abs(temp_abs, ref_file_name);
482
483         /* if file exists use it */
484         if (BLI_exists(temp_abs)) {
485           BKE_reportf(reports, RPT_INFO, "Use existing file (instead of packed): %s", abs_name);
486           temp = abs_name;
487           break;
488         }
489         /* else create it */
490         ATTR_FALLTHROUGH;
491       }
492       case PF_WRITE_ORIGINAL:
493         if (BKE_packedfile_write_to_file(reports, ref_file_name, abs_name, pf, 1) == RET_OK) {
494           temp = abs_name;
495         }
496         break;
497       default:
498         printf("%s: unknown return_value %u\n", __func__, how);
499         break;
500     }
501
502     if (temp) {
503       newname = BLI_strdup(temp);
504     }
505   }
506
507   return newname;
508 }
509
510 static void unpack_generate_paths(const char *name,
511                                   ID *id,
512                                   char *r_abspath,
513                                   char *r_relpath,
514                                   size_t abspathlen,
515                                   size_t relpathlen)
516 {
517   char tempname[FILE_MAX];
518   char tempdir[FILE_MAXDIR];
519
520   BLI_split_dirfile(name, tempdir, tempname, sizeof(tempdir), sizeof(tempname));
521
522   if (tempname[0] == '\0') {
523     /* Note: we do not have any real way to re-create extension out of data... */
524     BLI_strncpy(tempname, id->name + 2, sizeof(tempname));
525     printf("%s\n", tempname);
526     BLI_filename_make_safe(tempname);
527     printf("%s\n", tempname);
528   }
529
530   if (tempdir[0] == '\0') {
531     /* Fallback to relative dir. */
532     BLI_strncpy(tempdir, "//", sizeof(tempdir));
533   }
534
535   switch (GS(id->name)) {
536     case ID_VF:
537       BLI_snprintf(r_relpath, relpathlen, "//fonts/%s", tempname);
538       break;
539     case ID_SO:
540       BLI_snprintf(r_relpath, relpathlen, "//sounds/%s", tempname);
541       break;
542     case ID_IM:
543       BLI_snprintf(r_relpath, relpathlen, "//textures/%s", tempname);
544       break;
545     case ID_VO:
546       BLI_snprintf(r_relpath, relpathlen, "//volumes/%s", tempname);
547       break;
548     default:
549       break;
550   }
551
552   {
553     size_t len = BLI_strncpy_rlen(r_abspath, tempdir, abspathlen);
554     BLI_strncpy(r_abspath + len, tempname, abspathlen - len);
555   }
556 }
557
558 int BKE_packedfile_unpack_vfont(Main *bmain,
559                                 ReportList *reports,
560                                 VFont *vfont,
561                                 enum ePF_FileStatus how)
562 {
563   char localname[FILE_MAX], absname[FILE_MAX];
564   char *newname;
565   int ret_value = RET_ERROR;
566
567   if (vfont != NULL) {
568     unpack_generate_paths(
569         vfont->name, (ID *)vfont, absname, localname, sizeof(absname), sizeof(localname));
570     newname = BKE_packedfile_unpack_to_file(
571         reports, BKE_main_blendfile_path(bmain), absname, localname, vfont->packedfile, how);
572     if (newname != NULL) {
573       ret_value = RET_OK;
574       BKE_packedfile_free(vfont->packedfile);
575       vfont->packedfile = NULL;
576       BLI_strncpy(vfont->name, newname, sizeof(vfont->name));
577       MEM_freeN(newname);
578     }
579   }
580
581   return (ret_value);
582 }
583
584 int BKE_packedfile_unpack_sound(Main *bmain,
585                                 ReportList *reports,
586                                 bSound *sound,
587                                 enum ePF_FileStatus how)
588 {
589   char localname[FILE_MAX], absname[FILE_MAX];
590   char *newname;
591   int ret_value = RET_ERROR;
592
593   if (sound != NULL) {
594     unpack_generate_paths(
595         sound->name, (ID *)sound, absname, localname, sizeof(absname), sizeof(localname));
596     newname = BKE_packedfile_unpack_to_file(
597         reports, BKE_main_blendfile_path(bmain), absname, localname, sound->packedfile, how);
598     if (newname != NULL) {
599       BLI_strncpy(sound->name, newname, sizeof(sound->name));
600       MEM_freeN(newname);
601
602       BKE_packedfile_free(sound->packedfile);
603       sound->packedfile = NULL;
604
605       BKE_sound_load(bmain, sound);
606
607       ret_value = RET_OK;
608     }
609   }
610
611   return (ret_value);
612 }
613
614 int BKE_packedfile_unpack_image(Main *bmain,
615                                 ReportList *reports,
616                                 Image *ima,
617                                 enum ePF_FileStatus how)
618 {
619   int ret_value = RET_ERROR;
620
621   if (ima != NULL) {
622     while (ima->packedfiles.last) {
623       char localname[FILE_MAX], absname[FILE_MAX];
624       char *newname;
625       ImagePackedFile *imapf = ima->packedfiles.last;
626
627       unpack_generate_paths(
628           imapf->filepath, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname));
629       newname = BKE_packedfile_unpack_to_file(
630           reports, BKE_main_blendfile_path(bmain), absname, localname, imapf->packedfile, how);
631
632       if (newname != NULL) {
633         ImageView *iv;
634
635         ret_value = ret_value == RET_ERROR ? RET_ERROR : RET_OK;
636         BKE_packedfile_free(imapf->packedfile);
637         imapf->packedfile = NULL;
638
639         /* update the new corresponding view filepath */
640         iv = BLI_findstring(&ima->views, imapf->filepath, offsetof(ImageView, filepath));
641         if (iv) {
642           BLI_strncpy(iv->filepath, newname, sizeof(imapf->filepath));
643         }
644
645         /* keep the new name in the image for non-pack specific reasons */
646         if (how != PF_REMOVE) {
647           BLI_strncpy(ima->name, newname, sizeof(imapf->filepath));
648         }
649         MEM_freeN(newname);
650       }
651       else {
652         ret_value = RET_ERROR;
653       }
654
655       BLI_remlink(&ima->packedfiles, imapf);
656       MEM_freeN(imapf);
657     }
658   }
659
660   if (ret_value == RET_OK) {
661     BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_RELOAD);
662   }
663
664   return (ret_value);
665 }
666
667 int BKE_packedfile_unpack_volume(Main *bmain,
668                                  ReportList *reports,
669                                  Volume *volume,
670                                  enum ePF_FileStatus how)
671 {
672   char localname[FILE_MAX], absname[FILE_MAX];
673   char *newfilepath;
674   int ret_value = RET_ERROR;
675
676   if (volume != NULL) {
677     unpack_generate_paths(
678         volume->filepath, (ID *)volume, absname, localname, sizeof(absname), sizeof(localname));
679     newfilepath = BKE_packedfile_unpack_to_file(
680         reports, BKE_main_blendfile_path(bmain), absname, localname, volume->packedfile, how);
681     if (newfilepath != NULL) {
682       BLI_strncpy(volume->filepath, newfilepath, sizeof(volume->filepath));
683       MEM_freeN(newfilepath);
684
685       BKE_packedfile_free(volume->packedfile);
686       volume->packedfile = NULL;
687
688       BKE_volume_unload(volume);
689
690       ret_value = RET_OK;
691     }
692   }
693
694   return (ret_value);
695 }
696
697 int BKE_packedfile_unpack_all_libraries(Main *bmain, ReportList *reports)
698 {
699   Library *lib;
700   char *newname;
701   int ret_value = RET_ERROR;
702
703   for (lib = bmain->libraries.first; lib; lib = lib->id.next) {
704     if (lib->packedfile && lib->name[0]) {
705
706       newname = BKE_packedfile_unpack_to_file(reports,
707                                               BKE_main_blendfile_path(bmain),
708                                               lib->filepath_abs,
709                                               lib->filepath_abs,
710                                               lib->packedfile,
711                                               PF_WRITE_ORIGINAL);
712       if (newname != NULL) {
713         ret_value = RET_OK;
714
715         printf("Unpacked .blend library: %s\n", newname);
716
717         BKE_packedfile_free(lib->packedfile);
718         lib->packedfile = NULL;
719
720         MEM_freeN(newname);
721       }
722     }
723   }
724
725   return (ret_value);
726 }
727
728 void BKE_packedfile_pack_all_libraries(Main *bmain, ReportList *reports)
729 {
730   Library *lib;
731
732   /* test for relativenss */
733   for (lib = bmain->libraries.first; lib; lib = lib->id.next) {
734     if (!BLI_path_is_rel(lib->name)) {
735       break;
736     }
737   }
738
739   if (lib) {
740     BKE_reportf(reports, RPT_ERROR, "Cannot pack absolute file: '%s'", lib->name);
741     return;
742   }
743
744   for (lib = bmain->libraries.first; lib; lib = lib->id.next) {
745     if (lib->packedfile == NULL) {
746       lib->packedfile = BKE_packedfile_new(reports, lib->name, BKE_main_blendfile_path(bmain));
747     }
748   }
749 }
750
751 void BKE_packedfile_unpack_all(Main *bmain, ReportList *reports, enum ePF_FileStatus how)
752 {
753   Image *ima;
754   VFont *vf;
755   bSound *sound;
756   Volume *volume;
757
758   for (ima = bmain->images.first; ima; ima = ima->id.next) {
759     if (BKE_image_has_packedfile(ima)) {
760       BKE_packedfile_unpack_image(bmain, reports, ima, how);
761     }
762   }
763
764   for (vf = bmain->fonts.first; vf; vf = vf->id.next) {
765     if (vf->packedfile) {
766       BKE_packedfile_unpack_vfont(bmain, reports, vf, how);
767     }
768   }
769
770   for (sound = bmain->sounds.first; sound; sound = sound->id.next) {
771     if (sound->packedfile) {
772       BKE_packedfile_unpack_sound(bmain, reports, sound, how);
773     }
774   }
775
776   for (volume = bmain->volumes.first; volume; volume = volume->id.next) {
777     if (volume->packedfile) {
778       BKE_packedfile_unpack_volume(bmain, reports, volume, how);
779     }
780   }
781 }
782
783 /* ID should be not NULL, return 1 if there's a packed file */
784 bool BKE_packedfile_id_check(ID *id)
785 {
786   switch (GS(id->name)) {
787     case ID_IM: {
788       Image *ima = (Image *)id;
789       return BKE_image_has_packedfile(ima);
790     }
791     case ID_VF: {
792       VFont *vf = (VFont *)id;
793       return vf->packedfile != NULL;
794     }
795     case ID_SO: {
796       bSound *snd = (bSound *)id;
797       return snd->packedfile != NULL;
798     }
799     case ID_VO: {
800       Volume *volume = (Volume *)id;
801       return volume->packedfile != NULL;
802     }
803     case ID_LI: {
804       Library *li = (Library *)id;
805       return li->packedfile != NULL;
806     }
807     default:
808       break;
809   }
810   return false;
811 }
812
813 /* ID should be not NULL */
814 void BKE_packedfile_id_unpack(Main *bmain, ID *id, ReportList *reports, enum ePF_FileStatus how)
815 {
816   switch (GS(id->name)) {
817     case ID_IM: {
818       Image *ima = (Image *)id;
819       if (BKE_image_has_packedfile(ima)) {
820         BKE_packedfile_unpack_image(bmain, reports, ima, how);
821       }
822       break;
823     }
824     case ID_VF: {
825       VFont *vf = (VFont *)id;
826       if (vf->packedfile) {
827         BKE_packedfile_unpack_vfont(bmain, reports, vf, how);
828       }
829       break;
830     }
831     case ID_SO: {
832       bSound *snd = (bSound *)id;
833       if (snd->packedfile) {
834         BKE_packedfile_unpack_sound(bmain, reports, snd, how);
835       }
836       break;
837     }
838     case ID_VO: {
839       Volume *volume = (Volume *)id;
840       if (volume->packedfile) {
841         BKE_packedfile_unpack_volume(bmain, reports, volume, how);
842       }
843       break;
844     }
845     case ID_LI: {
846       Library *li = (Library *)id;
847       BKE_reportf(reports, RPT_ERROR, "Cannot unpack individual Library file, '%s'", li->name);
848       break;
849     }
850     default:
851       break;
852   }
853 }