Merge branch 'blender2.7'
[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 \ingroup bke
21  */
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 seekPackedFile(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 rewindPackedFile(PackedFile *pf)
85 {
86         seekPackedFile(pf, 0, SEEK_SET);
87 }
88
89 int readPackedFile(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 countPackedFiles(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->image.first; ima; ima = ima->id.next)
121                 if (BKE_image_has_packedfile(ima))
122                         count ++;
123
124         for (vf = bmain->vfont.first; vf; vf = vf->id.next)
125                 if (vf->packedfile)
126                         count++;
127
128         for (sound = bmain->sound.first; sound; sound = sound->id.next)
129                 if (sound->packedfile)
130                         count++;
131
132         return count;
133 }
134
135 void freePackedFile(PackedFile *pf)
136 {
137         if (pf) {
138                 MEM_freeN(pf->data);
139                 MEM_freeN(pf);
140         }
141         else
142                 printf("freePackedFile: Trying to free a NULL pointer\n");
143 }
144
145 PackedFile *dupPackedFile(const PackedFile *pf_src)
146 {
147         PackedFile *pf_dst;
148
149         pf_dst       = MEM_dupallocN(pf_src);
150         pf_dst->data = MEM_dupallocN(pf_src->data);
151
152         return pf_dst;
153 }
154
155 PackedFile *newPackedFileMemory(void *mem, int memlen)
156 {
157         PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
158         pf->data = mem;
159         pf->size = memlen;
160
161         return pf;
162 }
163
164 PackedFile *newPackedFile(ReportList *reports, const char *filename, const char *basepath)
165 {
166         PackedFile *pf = NULL;
167         int file, filelen;
168         char name[FILE_MAX];
169         void *data;
170
171         /* render result has no filename and can be ignored
172          * any other files with no name can be ignored too */
173         if (filename[0] == '\0')
174                 return NULL;
175
176         //XXX waitcursor(1);
177
178         /* convert relative filenames to absolute filenames */
179
180         BLI_strncpy(name, filename, sizeof(name));
181         BLI_path_abs(name, basepath);
182
183         /* open the file
184          * and create a PackedFile structure */
185
186         file = BLI_open(name, O_BINARY | O_RDONLY, 0);
187         if (file == -1) {
188                 BKE_reportf(reports, RPT_ERROR, "Unable to pack file, source path '%s' not found", name);
189         }
190         else {
191                 filelen = BLI_file_descriptor_size(file);
192
193                 if (filelen == 0) {
194                         /* MEM_mallocN complains about MEM_mallocN(0, "bla");
195                          * we don't care.... */
196                         data = MEM_mallocN(1, "packFile");
197                 }
198                 else {
199                         data = MEM_mallocN(filelen, "packFile");
200                 }
201                 if (read(file, data, filelen) == filelen) {
202                         pf = newPackedFileMemory(data, filelen);
203                 }
204                 else {
205                         MEM_freeN(data);
206                 }
207
208                 close(file);
209         }
210
211         //XXX waitcursor(0);
212
213         return (pf);
214 }
215
216 /* no libraries for now */
217 void packAll(Main *bmain, ReportList *reports, bool verbose)
218 {
219         Image *ima;
220         VFont *vfont;
221         bSound *sound;
222         int tot = 0;
223
224         for (ima = bmain->image.first; ima; ima = ima->id.next) {
225                 if (BKE_image_has_packedfile(ima) == false && !ID_IS_LINKED(ima)) {
226                         if (ima->source == IMA_SRC_FILE) {
227                                 BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id));
228                                 tot ++;
229                         }
230                         else if (BKE_image_is_animated(ima) && verbose) {
231                                 BKE_reportf(reports, RPT_WARNING, "Image '%s' skipped, movies and image sequences not supported",
232                                             ima->id.name + 2);
233                         }
234                 }
235         }
236
237         for (vfont = bmain->vfont.first; vfont; vfont = vfont->id.next) {
238                 if (vfont->packedfile == NULL && !ID_IS_LINKED(vfont) && BKE_vfont_is_builtin(vfont) == false) {
239                         vfont->packedfile = newPackedFile(reports, vfont->name, BKE_main_blendfile_path(bmain));
240                         tot ++;
241                 }
242         }
243
244         for (sound = bmain->sound.first; sound; sound = sound->id.next) {
245                 if (sound->packedfile == NULL && !ID_IS_LINKED(sound)) {
246                         sound->packedfile = newPackedFile(reports, sound->name, BKE_main_blendfile_path(bmain));
247                         tot++;
248                 }
249         }
250
251         if (tot > 0)
252                 BKE_reportf(reports, RPT_INFO, "Packed %d files", tot);
253         else if (verbose)
254                 BKE_report(reports, RPT_INFO, "No new files have been packed");
255 }
256
257 int writePackedFile(
258         ReportList *reports, const char *ref_file_name, const char *filename, PackedFile *pf, const bool guimode)
259 {
260         int file, number;
261         int ret_value = RET_OK;
262         bool remove_tmp = false;
263         char name[FILE_MAX];
264         char tempname[FILE_MAX];
265 /*      void *data; */
266
267         if (guimode) {} //XXX  waitcursor(1);
268
269         BLI_strncpy(name, filename, sizeof(name));
270         BLI_path_abs(name, ref_file_name);
271
272         if (BLI_exists(name)) {
273                 for (number = 1; number <= 999; number++) {
274                         BLI_snprintf(tempname, sizeof(tempname), "%s.%03d_", name, number);
275                         if (!BLI_exists(tempname)) {
276                                 if (BLI_copy(name, tempname) == RET_OK) {
277                                         remove_tmp = true;
278                                 }
279                                 break;
280                         }
281                 }
282         }
283
284         /* make sure the path to the file exists... */
285         BLI_make_existing_file(name);
286
287         file = BLI_open(name, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666);
288         if (file == -1) {
289                 BKE_reportf(reports, RPT_ERROR, "Error creating file '%s'", name);
290                 ret_value = RET_ERROR;
291         }
292         else {
293                 if (write(file, pf->data, pf->size) != pf->size) {
294                         BKE_reportf(reports, RPT_ERROR, "Error writing file '%s'", name);
295                         ret_value = RET_ERROR;
296                 }
297                 else {
298                         BKE_reportf(reports, RPT_INFO, "Saved packed file to: %s", name);
299                 }
300
301                 close(file);
302         }
303
304         if (remove_tmp) {
305                 if (ret_value == RET_ERROR) {
306                         if (BLI_rename(tempname, name) != 0) {
307                                 BKE_reportf(reports, RPT_ERROR, "Error restoring temp file (check files '%s' '%s')", tempname, name);
308                         }
309                 }
310                 else {
311                         if (BLI_delete(tempname, false, false) != 0) {
312                                 BKE_reportf(reports, RPT_ERROR, "Error deleting '%s' (ignored)", tempname);
313                         }
314                 }
315         }
316
317         if (guimode) {} //XXX waitcursor(0);
318
319         return (ret_value);
320 }
321
322 /**
323  * This function compares a packed file to a 'real' file.
324  * It returns an integer indicating if:
325  *
326  * - PF_EQUAL:     the packed file and original file are identical
327  * - PF_DIFFERENT: the packed file and original file differ
328  * - PF_NOFILE:    the original file doesn't exist
329  */
330 int checkPackedFile(const char *ref_file_name, const char *filename, PackedFile *pf)
331 {
332         BLI_stat_t st;
333         int ret_val, i, len, file;
334         char buf[4096];
335         char name[FILE_MAX];
336
337         BLI_strncpy(name, filename, sizeof(name));
338         BLI_path_abs(name, ref_file_name);
339
340         if (BLI_stat(name, &st) == -1) {
341                 ret_val = PF_NOFILE;
342         }
343         else if (st.st_size != pf->size) {
344                 ret_val = PF_DIFFERS;
345         }
346         else {
347                 /* we'll have to compare the two... */
348
349                 file = BLI_open(name, O_BINARY | O_RDONLY, 0);
350                 if (file == -1) {
351                         ret_val = PF_NOFILE;
352                 }
353                 else {
354                         ret_val = PF_EQUAL;
355
356                         for (i = 0; i < pf->size; i += sizeof(buf)) {
357                                 len = pf->size - i;
358                                 if (len > sizeof(buf)) {
359                                         len = sizeof(buf);
360                                 }
361
362                                 if (read(file, buf, len) != len) {
363                                         /* read error ... */
364                                         ret_val = PF_DIFFERS;
365                                         break;
366                                 }
367                                 else {
368                                         if (memcmp(buf, ((char *)pf->data) + i, len)) {
369                                                 ret_val = PF_DIFFERS;
370                                                 break;
371                                         }
372                                 }
373                         }
374
375                         close(file);
376                 }
377         }
378
379         return(ret_val);
380 }
381
382 /**
383  * unpackFile() looks at the existing files (abs_name, local_name) and a packed file.
384  *
385  * It returns a char *to the existing file name / new file name or NULL when
386  * there was an error or when the user decides to cancel the operation.
387  *
388  * \warning 'abs_name' may be relative still! (use a "//" prefix) be sure to run #BLI_path_abs on it first.
389  */
390 char *unpackFile(
391         ReportList *reports, const char *ref_file_name,
392         const char *abs_name, const char *local_name, PackedFile *pf, int how)
393 {
394         char *newname = NULL;
395         const char *temp = NULL;
396
397         if (pf != NULL) {
398                 switch (how) {
399                         case -1:
400                         case PF_KEEP:
401                                 break;
402                         case PF_REMOVE:
403                                 temp = abs_name;
404                                 break;
405                         case PF_USE_LOCAL:
406                         {
407                                 char temp_abs[FILE_MAX];
408
409                                 BLI_strncpy(temp_abs, local_name, sizeof(temp_abs));
410                                 BLI_path_abs(temp_abs, ref_file_name);
411
412                                 /* if file exists use it */
413                                 if (BLI_exists(temp_abs)) {
414                                         temp = local_name;
415                                         break;
416                                 }
417                                 /* else create it */
418                                 ATTR_FALLTHROUGH;
419                         }
420                         case PF_WRITE_LOCAL:
421                                 if (writePackedFile(reports, ref_file_name, local_name, pf, 1) == RET_OK) {
422                                         temp = local_name;
423                                 }
424                                 break;
425                         case PF_USE_ORIGINAL:
426                         {
427                                 char temp_abs[FILE_MAX];
428
429                                 BLI_strncpy(temp_abs, abs_name, sizeof(temp_abs));
430                                 BLI_path_abs(temp_abs, ref_file_name);
431
432                                 /* if file exists use it */
433                                 if (BLI_exists(temp_abs)) {
434                                         BKE_reportf(reports, RPT_INFO, "Use existing file (instead of packed): %s", abs_name);
435                                         temp = abs_name;
436                                         break;
437                                 }
438                                 /* else create it */
439                                 ATTR_FALLTHROUGH;
440                         }
441                         case PF_WRITE_ORIGINAL:
442                                 if (writePackedFile(reports, ref_file_name, abs_name, pf, 1) == RET_OK) {
443                                         temp = abs_name;
444                                 }
445                                 break;
446                         default:
447                                 printf("unpackFile: unknown return_value %d\n", how);
448                                 break;
449                 }
450
451                 if (temp) {
452                         newname = BLI_strdup(temp);
453                 }
454         }
455
456         return newname;
457 }
458
459 static void unpack_generate_paths(
460         const char *name, ID *id, char *r_abspath, char *r_relpath, size_t abspathlen, size_t relpathlen)
461 {
462         char tempname[FILE_MAX];
463         char tempdir[FILE_MAXDIR];
464
465         BLI_split_dirfile(name, tempdir, tempname, sizeof(tempdir), sizeof(tempname));
466
467         if (tempname[0] == '\0') {
468                 /* Note: we do not have any real way to re-create extension out of data... */
469                 BLI_strncpy(tempname, id->name + 2, sizeof(tempname));
470                 printf("%s\n", tempname);
471                 BLI_filename_make_safe(tempname);
472                 printf("%s\n", tempname);
473         }
474
475         if (tempdir[0] == '\0') {
476                 /* Fallback to relative dir. */
477                 BLI_strncpy(tempdir, "//", sizeof(tempdir));
478         }
479
480         switch (GS(id->name)) {
481                 case ID_VF:
482                         BLI_snprintf(r_relpath, relpathlen, "//fonts/%s", tempname);
483                         break;
484                 case ID_SO:
485                         BLI_snprintf(r_relpath, relpathlen, "//sounds/%s", tempname);
486                         break;
487                 case ID_IM:
488                         BLI_snprintf(r_relpath, relpathlen, "//textures/%s", tempname);
489                         break;
490                 default:
491                         break;
492         }
493
494         {
495                 size_t len = BLI_strncpy_rlen(r_abspath, tempdir, abspathlen);
496                 BLI_strncpy(r_abspath + len, tempname, abspathlen - len);
497         }
498 }
499
500 int unpackVFont(Main *bmain, ReportList *reports, VFont *vfont, int how)
501 {
502         char localname[FILE_MAX], absname[FILE_MAX];
503         char *newname;
504         int ret_value = RET_ERROR;
505
506         if (vfont != NULL) {
507                 unpack_generate_paths(vfont->name, (ID *)vfont, absname, localname, sizeof(absname), sizeof(localname));
508                 newname = unpackFile(reports, BKE_main_blendfile_path(bmain), absname, localname, vfont->packedfile, how);
509                 if (newname != NULL) {
510                         ret_value = RET_OK;
511                         freePackedFile(vfont->packedfile);
512                         vfont->packedfile = NULL;
513                         BLI_strncpy(vfont->name, newname, sizeof(vfont->name));
514                         MEM_freeN(newname);
515                 }
516         }
517
518         return (ret_value);
519 }
520
521 int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how)
522 {
523         char localname[FILE_MAX], absname[FILE_MAX];
524         char *newname;
525         int ret_value = RET_ERROR;
526
527         if (sound != NULL) {
528                 unpack_generate_paths(sound->name, (ID *)sound, absname, localname, sizeof(absname), sizeof(localname));
529                 newname = unpackFile(reports, BKE_main_blendfile_path(bmain), absname, localname, sound->packedfile, how);
530                 if (newname != NULL) {
531                         BLI_strncpy(sound->name, newname, sizeof(sound->name));
532                         MEM_freeN(newname);
533
534                         freePackedFile(sound->packedfile);
535                         sound->packedfile = NULL;
536
537                         BKE_sound_load(bmain, sound);
538
539                         ret_value = RET_OK;
540                 }
541         }
542
543         return(ret_value);
544 }
545
546 int unpackImage(Main *bmain, ReportList *reports, Image *ima, int how)
547 {
548         int ret_value = RET_ERROR;
549
550         if (ima != NULL) {
551                 while (ima->packedfiles.last) {
552                         char localname[FILE_MAX], absname[FILE_MAX];
553                         char *newname;
554                         ImagePackedFile *imapf = ima->packedfiles.last;
555
556                         unpack_generate_paths(imapf->filepath, (ID *)ima, absname, localname, sizeof(absname), sizeof(localname));
557                         newname = unpackFile(reports, BKE_main_blendfile_path(bmain), absname, localname, imapf->packedfile, how);
558
559                         if (newname != NULL) {
560                                 ImageView *iv;
561
562                                 ret_value = ret_value == RET_ERROR ? RET_ERROR : RET_OK;
563                                 freePackedFile(imapf->packedfile);
564                                 imapf->packedfile = NULL;
565
566                                 /* update the new corresponding view filepath */
567                                 iv = BLI_findstring(&ima->views, imapf->filepath, offsetof(ImageView, filepath));
568                                 if (iv) {
569                                         BLI_strncpy(iv->filepath, newname, sizeof(imapf->filepath));
570                                 }
571
572                                 /* keep the new name in the image for non-pack specific reasons */
573                                 if (how != PF_REMOVE) {
574                                         BLI_strncpy(ima->name, newname, sizeof(imapf->filepath));
575                                 }
576                                 MEM_freeN(newname);
577                         }
578                         else {
579                                 ret_value = RET_ERROR;
580                         }
581
582                         BLI_remlink(&ima->packedfiles, imapf);
583                         MEM_freeN(imapf);
584                 }
585         }
586
587         if (ret_value == RET_OK) {
588                 BKE_image_signal(bmain, ima, NULL, IMA_SIGNAL_RELOAD);
589         }
590
591         return(ret_value);
592 }
593
594 int unpackLibraries(Main *bmain, ReportList *reports)
595 {
596         Library *lib;
597         char *newname;
598         int ret_value = RET_ERROR;
599
600         for (lib = bmain->library.first; lib; lib = lib->id.next) {
601                 if (lib->packedfile && lib->name[0]) {
602
603                         newname = unpackFile(reports, BKE_main_blendfile_path(bmain), lib->filepath, lib->filepath, lib->packedfile, PF_WRITE_ORIGINAL);
604                         if (newname != NULL) {
605                                 ret_value = RET_OK;
606
607                                 printf("Unpacked .blend library: %s\n", newname);
608
609                                 freePackedFile(lib->packedfile);
610                                 lib->packedfile = NULL;
611
612                                 MEM_freeN(newname);
613                         }
614                 }
615         }
616
617         return(ret_value);
618 }
619
620 void packLibraries(Main *bmain, ReportList *reports)
621 {
622         Library *lib;
623
624         /* test for relativenss */
625         for (lib = bmain->library.first; lib; lib = lib->id.next)
626                 if (!BLI_path_is_rel(lib->name))
627                         break;
628
629         if (lib) {
630                 BKE_reportf(reports, RPT_ERROR, "Cannot pack absolute file: '%s'", lib->name);
631                 return;
632         }
633
634         for (lib = bmain->library.first; lib; lib = lib->id.next)
635                 if (lib->packedfile == NULL)
636                         lib->packedfile = newPackedFile(reports, lib->name, BKE_main_blendfile_path(bmain));
637 }
638
639 void unpackAll(Main *bmain, ReportList *reports, int how)
640 {
641         Image *ima;
642         VFont *vf;
643         bSound *sound;
644
645         for (ima = bmain->image.first; ima; ima = ima->id.next)
646                 if (BKE_image_has_packedfile(ima))
647                         unpackImage(bmain, reports, ima, how);
648
649         for (vf = bmain->vfont.first; vf; vf = vf->id.next)
650                 if (vf->packedfile)
651                         unpackVFont(bmain, reports, vf, how);
652
653         for (sound = bmain->sound.first; sound; sound = sound->id.next)
654                 if (sound->packedfile)
655                         unpackSound(bmain, reports, sound, how);
656 }
657
658 /* ID should be not NULL, return 1 if there's a packed file */
659 bool BKE_pack_check(ID *id)
660 {
661         switch (GS(id->name)) {
662                 case ID_IM:
663                 {
664                         Image *ima = (Image *)id;
665                         return BKE_image_has_packedfile(ima);
666                 }
667                 case ID_VF:
668                 {
669                         VFont *vf = (VFont *)id;
670                         return vf->packedfile != NULL;
671                 }
672                 case ID_SO:
673                 {
674                         bSound *snd = (bSound *)id;
675                         return snd->packedfile != NULL;
676                 }
677                 case ID_LI:
678                 {
679                         Library *li = (Library *)id;
680                         return li->packedfile != NULL;
681                 }
682                 default:
683                         break;
684         }
685         return false;
686 }
687
688 /* ID should be not NULL */
689 void BKE_unpack_id(Main *bmain, ID *id, ReportList *reports, int how)
690 {
691         switch (GS(id->name)) {
692                 case ID_IM:
693                 {
694                         Image *ima = (Image *)id;
695                         if (BKE_image_has_packedfile(ima)) {
696                                 unpackImage(bmain, reports, ima, how);
697                         }
698                         break;
699                 }
700                 case ID_VF:
701                 {
702                         VFont *vf = (VFont *)id;
703                         if (vf->packedfile) {
704                                 unpackVFont(bmain, reports, vf, how);
705                         }
706                         break;
707                 }
708                 case ID_SO:
709                 {
710                         bSound *snd = (bSound *)id;
711                         if (snd->packedfile) {
712                                 unpackSound(bmain, reports, snd, how);
713                         }
714                         break;
715                 }
716                 case ID_LI:
717                 {
718                         Library *li = (Library *)id;
719                         BKE_reportf(reports, RPT_ERROR, "Cannot unpack individual Library file, '%s'", li->name);
720                         break;
721                 }
722                 default:
723                         break;
724         }
725 }