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