Code Cleanup: replace checks for ima->source with BKE_image_is_animated
[blender.git] / source / blender / blenkernel / intern / packedFile.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/blenkernel/intern/packedFile.c
29  *  \ingroup bke
30  */
31
32
33 #include <stdio.h>
34 #include <fcntl.h>
35 #include <sys/stat.h>
36
37 #ifndef WIN32 
38 #include <unistd.h>
39 #else
40 #include <io.h>
41 #endif
42 #include <string.h>
43 #include "MEM_guardedalloc.h"
44
45 #include "DNA_image_types.h"
46 #include "DNA_ID.h"
47 #include "DNA_packedFile_types.h"
48 #include "DNA_sound_types.h"
49 #include "DNA_vfont_types.h"
50
51 #include "BLI_blenlib.h"
52 #include "BLI_utildefines.h"
53
54 #include "BKE_font.h"
55 #include "BKE_global.h"
56 #include "BKE_image.h"
57 #include "BKE_main.h"
58 #include "BKE_packedFile.h"
59 #include "BKE_report.h"
60 #include "BKE_sound.h"
61
62 #ifdef _WIN32
63 #define open _open
64 #define close _close
65 #define read _read
66 #define write _write
67 #endif
68
69
70 int seekPackedFile(PackedFile *pf, int offset, int whence)
71 {
72         int oldseek = -1, seek = 0;
73
74         if (pf) {
75                 oldseek = pf->seek;
76                 switch (whence) {
77                         case SEEK_CUR:
78                                 seek = oldseek + offset;
79                                 break;
80                         case SEEK_END:
81                                 seek = pf->size + offset;
82                                 break;
83                         case SEEK_SET:
84                                 seek = offset;
85                                 break;
86                         default:
87                                 oldseek = -1;
88                                 break;
89                 }
90                 if (seek < 0) {
91                         seek = 0;
92                 }
93                 else if (seek > pf->size) {
94                         seek = pf->size;
95                 }
96                 pf->seek = seek;
97         }
98
99         return(oldseek);
100 }
101         
102 void rewindPackedFile(PackedFile *pf)
103 {
104         seekPackedFile(pf, 0, SEEK_SET);
105 }
106
107 int readPackedFile(PackedFile *pf, void *data, int size)
108
109         if ((pf != NULL) && (size >= 0) && (data != NULL)) {
110                 if (size + pf->seek > pf->size) {
111                         size = pf->size - pf->seek;
112                 }
113
114                 if (size > 0) {
115                         memcpy(data, ((char *) pf->data) + pf->seek, size);
116                 }
117                 else {
118                         size = 0;
119                 }
120
121                 pf->seek += size;
122         }
123         else {
124                 size = -1;
125         }
126
127         return(size);
128 }
129
130 int countPackedFiles(Main *bmain)
131 {
132         Image *ima;
133         VFont *vf;
134         bSound *sound;
135         int count = 0;
136         
137         /* let's check if there are packed files... */
138         for (ima = bmain->image.first; ima; ima = ima->id.next)
139                 if (ima->packedfile)
140                         count++;
141
142         for (vf = bmain->vfont.first; vf; vf = vf->id.next)
143                 if (vf->packedfile)
144                         count++;
145
146         for (sound = bmain->sound.first; sound; sound = sound->id.next)
147                 if (sound->packedfile)
148                         count++;
149
150         return count;
151 }
152
153 void freePackedFile(PackedFile *pf)
154 {
155         if (pf) {
156                 MEM_freeN(pf->data);
157                 MEM_freeN(pf);
158         }
159         else
160                 printf("freePackedFile: Trying to free a NULL pointer\n");
161 }
162
163 PackedFile *dupPackedFile(const PackedFile *pf_src)
164 {
165         PackedFile *pf_dst;
166
167         pf_dst       = MEM_dupallocN(pf_src);
168         pf_dst->data = MEM_dupallocN(pf_src->data);
169
170         return pf_dst;
171 }
172
173 PackedFile *newPackedFileMemory(void *mem, int memlen)
174 {
175         PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
176         pf->data = mem;
177         pf->size = memlen;
178         
179         return pf;
180 }
181
182 PackedFile *newPackedFile(ReportList *reports, const char *filename, const char *basepath)
183 {
184         PackedFile *pf = NULL;
185         int file, filelen;
186         char name[FILE_MAX];
187         void *data;
188         
189         /* render result has no filename and can be ignored
190          * any other files with no name can be ignored too */
191         if (filename[0] == '\0')
192                 return NULL;
193
194         //XXX waitcursor(1);
195         
196         /* convert relative filenames to absolute filenames */
197
198         BLI_strncpy(name, filename, sizeof(name));
199         BLI_path_abs(name, basepath);
200
201         /* open the file
202          * and create a PackedFile structure */
203
204         file = BLI_open(name, O_BINARY | O_RDONLY, 0);
205         if (file < 0) {
206                 BKE_reportf(reports, RPT_ERROR, "Unable to pack file, source path '%s' not found", name);
207         }
208         else {
209                 filelen = BLI_file_descriptor_size(file);
210
211                 if (filelen == 0) {
212                         /* MEM_mallocN complains about MEM_mallocN(0, "bla");
213                          * we don't care.... */
214                         data = MEM_mallocN(1, "packFile");
215                 }
216                 else {
217                         data = MEM_mallocN(filelen, "packFile");
218                 }
219                 if (read(file, data, filelen) == filelen) {
220                         pf = newPackedFileMemory(data, filelen);
221                 }
222                 else {
223                         MEM_freeN(data);
224                 }
225
226                 close(file);
227         }
228
229         //XXX waitcursor(0);
230                 
231         return (pf);
232 }
233
234 /* no libraries for now */
235 void packAll(Main *bmain, ReportList *reports)
236 {
237         Image *ima;
238         VFont *vfont;
239         bSound *sound;
240         int tot = 0;
241         
242         for (ima = bmain->image.first; ima; ima = ima->id.next) {
243                 if (ima->packedfile == NULL && ima->id.lib == NULL) {
244                         if (ima->source == IMA_SRC_FILE) {
245                                 ima->packedfile = newPackedFile(reports, ima->name, ID_BLEND_PATH(bmain, &ima->id));
246                                 tot ++;
247                         }
248                         else if (BKE_image_is_animated(ima)) {
249                                 BKE_reportf(reports, RPT_WARNING, "Image '%s' skipped, movies and image sequences not supported",
250                                             ima->id.name + 2);
251                         }
252                 }
253         }
254
255         for (vfont = bmain->vfont.first; vfont; vfont = vfont->id.next) {
256                 if (vfont->packedfile == NULL && vfont->id.lib == NULL && BKE_vfont_is_builtin(vfont) == FALSE) {
257                         vfont->packedfile = newPackedFile(reports, vfont->name, bmain->name);
258                         tot ++;
259                 }
260         }
261
262         for (sound = bmain->sound.first; sound; sound = sound->id.next) {
263                 if (sound->packedfile == NULL && sound->id.lib == NULL) {
264                         sound->packedfile = newPackedFile(reports, sound->name, bmain->name);
265                         tot++;
266                 }
267         }
268         
269         if (tot == 0)
270                 BKE_report(reports, RPT_INFO, "No new files have been packed");
271         else
272                 BKE_reportf(reports, RPT_INFO, "Packed %d files", tot);
273
274
275 }
276
277
278 #if 0
279
280 // attempt to create a function that generates an unique filename
281 // this will work when all funtions in fileops.c understand relative filenames...
282
283 static char *find_new_name(char *name)
284 {
285         char tempname[FILE_MAX];
286         char *newname;
287         size_t len;
288         
289         if (fop_exists(name)) {
290                 for (number = 1; number <= 999; number++) {
291                         BLI_snprintf(tempname, sizeof(tempname), "%s.%03d", name, number);
292                         if (!fop_exists(tempname)) {
293                                 break;
294                         }
295                 }
296         }
297         len = strlen(tempname) + 1;
298         newname = MEM_mallocN(len, "find_new_name");
299         memcpy(newname, tempname, len * sizeof(char));
300         return newname;
301 }
302 #endif
303
304 int writePackedFile(ReportList *reports, const char *filename, PackedFile *pf, int guimode)
305 {
306         int file, number, remove_tmp = FALSE;
307         int ret_value = RET_OK;
308         char name[FILE_MAX];
309         char tempname[FILE_MAX];
310 /*      void *data; */
311         
312         if (guimode) {} //XXX  waitcursor(1);
313         
314         BLI_strncpy(name, filename, sizeof(name));
315         BLI_path_abs(name, G.main->name);
316         
317         if (BLI_exists(name)) {
318                 for (number = 1; number <= 999; number++) {
319                         BLI_snprintf(tempname, sizeof(tempname), "%s.%03d_", name, number);
320                         if (!BLI_exists(tempname)) {
321                                 if (BLI_copy(name, tempname) == RET_OK) {
322                                         remove_tmp = TRUE;
323                                 }
324                                 break;
325                         }
326                 }
327         }
328         
329         /* make sure the path to the file exists... */
330         BLI_make_existing_file(name);
331         
332         file = BLI_open(name, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666);
333         if (file < 0) {
334                 BKE_reportf(reports, RPT_ERROR, "Error creating file '%s'", name);
335                 ret_value = RET_ERROR;
336         }
337         else {
338                 if (write(file, pf->data, pf->size) != pf->size) {
339                         BKE_reportf(reports, RPT_ERROR, "Error writing file '%s'", name);
340                         ret_value = RET_ERROR;
341                 }
342                 else {
343                         BKE_reportf(reports, RPT_INFO, "Saved packed file to: %s", name);
344                 }
345                 
346                 close(file);
347         }
348         
349         if (remove_tmp) {
350                 if (ret_value == RET_ERROR) {
351                         if (BLI_rename(tempname, name) != 0) {
352                                 BKE_reportf(reports, RPT_ERROR, "Error restoring temp file (check files '%s' '%s')", tempname, name);
353                         }
354                 }
355                 else {
356                         if (BLI_delete(tempname, false, false) != 0) {
357                                 BKE_reportf(reports, RPT_ERROR, "Error deleting '%s' (ignored)", tempname);
358                         }
359                 }
360         }
361         
362         if (guimode) {} //XXX waitcursor(0);
363
364         return (ret_value);
365 }
366         
367 /*
368  * This function compares a packed file to a 'real' file.
369  * It returns an integer indicating if:
370  *
371  * PF_EQUAL             - the packed file and original file are identical
372  * PF_DIFFERENT - the packed file and original file differ
373  * PF_NOFILE    - the original file doens't exist
374  */
375
376 int checkPackedFile(const char *filename, PackedFile *pf)
377 {
378         struct stat st;
379         int ret_val, i, len, file;
380         char buf[4096];
381         char name[FILE_MAX];
382         
383         BLI_strncpy(name, filename, sizeof(name));
384         BLI_path_abs(name, G.main->name);
385         
386         if (BLI_stat(name, &st)) {
387                 ret_val = PF_NOFILE;
388         }
389         else if (st.st_size != pf->size) {
390                 ret_val = PF_DIFFERS;
391         }
392         else {
393                 /* we'll have to compare the two... */
394
395                 file = BLI_open(name, O_BINARY | O_RDONLY, 0);
396                 if (file < 0) {
397                         ret_val = PF_NOFILE;
398                 }
399                 else {
400                         ret_val = PF_EQUAL;
401
402                         for (i = 0; i < pf->size; i += sizeof(buf)) {
403                                 len = pf->size - i;
404                                 if (len > sizeof(buf)) {
405                                         len = sizeof(buf);
406                                 }
407
408                                 if (read(file, buf, len) != len) {
409                                         /* read error ... */
410                                         ret_val = PF_DIFFERS;
411                                         break;
412                                 }
413                                 else {
414                                         if (memcmp(buf, ((char *)pf->data) + i, len)) {
415                                                 ret_val = PF_DIFFERS;
416                                                 break;
417                                         }
418                                 }
419                         }
420                         
421                         close(file);
422                 }
423         }
424         
425         return(ret_val);
426 }
427
428 /* unpackFile() looks at the existing files (abs_name, local_name) and a packed file.
429  *
430  * It returns a char *to the existing file name / new file name or NULL when
431  * there was an error or when the user decides to cancel the operation.
432  */
433
434 char *unpackFile(ReportList *reports, const char *abs_name, const char *local_name, PackedFile *pf, int how)
435 {
436         char *newname = NULL;
437         const char *temp = NULL;
438         
439         // char newabs[FILE_MAX];
440         // char newlocal[FILE_MAX];
441         
442         if (pf != NULL) {
443                 switch (how) {
444                         case -1:
445                         case PF_KEEP:
446                                 break;
447                         case PF_REMOVE:
448                                 temp = abs_name;
449                                 break;
450                         case PF_USE_LOCAL:
451                                 /* if file exists use it */
452                                 if (BLI_exists(local_name)) {
453                                         temp = local_name;
454                                         break;
455                                 }
456                                 /* else create it */
457                                 /* fall-through */
458                         case PF_WRITE_LOCAL:
459                                 if (writePackedFile(reports, local_name, pf, 1) == RET_OK) {
460                                         temp = local_name;
461                                 }
462                                 break;
463                         case PF_USE_ORIGINAL:
464                                 /* if file exists use it */
465                                 if (BLI_exists(abs_name)) {
466                                         BKE_reportf(reports, RPT_INFO, "Use existing file (instead of packed): %s", abs_name);
467                                         temp = abs_name;
468                                         break;
469                                 }
470                                 /* else create it */
471                                 /* fall-through */
472                         case PF_WRITE_ORIGINAL:
473                                 if (writePackedFile(reports, abs_name, pf, 1) == RET_OK) {
474                                         temp = abs_name;
475                                 }
476                                 break;
477                         default:
478                                 printf("unpackFile: unknown return_value %d\n", how);
479                                 break;
480                 }
481                 
482                 if (temp) {
483                         newname = BLI_strdup(temp);
484                 }
485         }
486         
487         return newname;
488 }
489
490
491 int unpackVFont(ReportList *reports, VFont *vfont, int how)
492 {
493         char localname[FILE_MAX], fi[FILE_MAXFILE];
494         char *newname;
495         int ret_value = RET_ERROR;
496         
497         if (vfont != NULL) {
498                 BLI_split_file_part(vfont->name, fi, sizeof(fi));
499                 BLI_snprintf(localname, sizeof(localname), "//fonts/%s", fi);
500                 newname = unpackFile(reports, vfont->name, localname, vfont->packedfile, how);
501                 if (newname != NULL) {
502                         ret_value = RET_OK;
503                         freePackedFile(vfont->packedfile);
504                         vfont->packedfile = NULL;
505                         BLI_strncpy(vfont->name, newname, sizeof(vfont->name));
506                         MEM_freeN(newname);
507                 }
508         }
509         
510         return (ret_value);
511 }
512
513 int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how)
514 {
515         char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
516         char *newname;
517         int ret_value = RET_ERROR;
518
519         if (sound != NULL) {
520                 BLI_split_file_part(sound->name, fi, sizeof(fi));
521                 BLI_snprintf(localname, sizeof(localname), "//sounds/%s", fi);
522                 newname = unpackFile(reports, sound->name, localname, sound->packedfile, how);
523                 if (newname != NULL) {
524                         BLI_strncpy(sound->name, newname, sizeof(sound->name));
525                         MEM_freeN(newname);
526
527                         freePackedFile(sound->packedfile);
528                         sound->packedfile = NULL;
529
530                         sound_load(bmain, sound);
531
532                         ret_value = RET_OK;
533                 }
534         }
535         
536         return(ret_value);
537 }
538
539 int unpackImage(ReportList *reports, Image *ima, int how)
540 {
541         char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
542         char *newname;
543         int ret_value = RET_ERROR;
544         
545         if (ima != NULL && ima->name[0]) {
546                 BLI_split_file_part(ima->name, fi, sizeof(fi));
547                 BLI_snprintf(localname, sizeof(localname), "//textures/%s", fi);
548                 newname = unpackFile(reports, ima->name, localname, ima->packedfile, how);
549                 if (newname != NULL) {
550                         ret_value = RET_OK;
551                         freePackedFile(ima->packedfile);
552                         ima->packedfile = NULL;
553                         BLI_strncpy(ima->name, newname, sizeof(ima->name));
554                         MEM_freeN(newname);
555                         BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
556                 }
557         }
558         
559         return(ret_value);
560 }
561
562 int unpackLibraries(Main *bmain, ReportList *reports)
563 {
564         Library *lib;
565         char *newname;
566         int ret_value = RET_ERROR;
567         
568         for (lib = bmain->library.first; lib; lib = lib->id.next) {
569                 if (lib->packedfile && lib->name[0]) {
570                         
571                         newname = unpackFile(reports, lib->filepath, lib->filepath, lib->packedfile, PF_WRITE_ORIGINAL);
572                         if (newname != NULL) {
573                                 ret_value = RET_OK;
574                                 
575                                 printf("Unpacked .blend library: %s\n", newname);
576                                 
577                                 freePackedFile(lib->packedfile);
578                                 lib->packedfile = NULL;
579
580                                 MEM_freeN(newname);
581                         }
582                 }
583         }
584         
585         return(ret_value);
586 }
587
588 void packLibraries(Main *bmain, ReportList *reports)
589 {
590         Library *lib;
591         
592         /* test for relativenss */
593         for (lib = bmain->library.first; lib; lib = lib->id.next)
594                 if (!BLI_path_is_rel(lib->name))
595                         break;
596         
597         if (lib) {
598                 BKE_reportf(reports, RPT_ERROR, "Cannot pack absolute file: '%s'", lib->name);
599                 return;
600         }
601         
602         for (lib = bmain->library.first; lib; lib = lib->id.next)
603                 if (lib->packedfile == NULL)
604                         lib->packedfile = newPackedFile(reports, lib->name, bmain->name);
605 }
606
607 void unpackAll(Main *bmain, ReportList *reports, int how)
608 {
609         Image *ima;
610         VFont *vf;
611         bSound *sound;
612
613         for (ima = bmain->image.first; ima; ima = ima->id.next)
614                 if (ima->packedfile)
615                         unpackImage(reports, ima, how);
616
617         for (vf = bmain->vfont.first; vf; vf = vf->id.next)
618                 if (vf->packedfile)
619                         unpackVFont(reports, vf, how);
620
621         for (sound = bmain->sound.first; sound; sound = sound->id.next)
622                 if (sound->packedfile)
623                         unpackSound(bmain, reports, sound, how);
624 }
625
626 /* ID should be not NULL, return 1 if there's a packed file */
627 bool BKE_pack_check(ID *id)
628 {
629         if (GS(id->name) == ID_IM) {
630                 Image *ima = (Image *)id;
631                 return ima->packedfile != NULL;
632         }
633         if (GS(id->name) == ID_VF) {
634                 VFont *vf = (VFont *)id;
635                 return vf->packedfile != NULL;
636         }
637         if (GS(id->name) == ID_SO) {
638                 bSound *snd = (bSound *)id;
639                 return snd->packedfile != NULL;
640         }
641         if (GS(id->name) == ID_LI) {
642                 Library *li = (Library *)id;
643                 return li->packedfile != NULL;
644         }
645         return false;
646 }
647
648 /* ID should be not NULL */
649 void BKE_unpack_id(Main *bmain, ID *id, ReportList *reports, int how)
650 {
651         if (GS(id->name) == ID_IM) {
652                 Image *ima = (Image *)id;
653                 if (ima->packedfile)
654                         unpackImage(reports, ima, how);
655         }
656         if (GS(id->name) == ID_VF) {
657                 VFont *vf = (VFont *)id;
658                 if (vf->packedfile)
659                         unpackVFont(reports, vf, how);
660         }
661         if (GS(id->name) == ID_SO) {
662                 bSound *snd = (bSound *)id;
663                 if (snd->packedfile)
664                         unpackSound(bmain, reports, snd, how);
665         }
666         if (GS(id->name) == ID_LI) {
667                 Library *li = (Library *)id;
668                 BKE_reportf(reports, RPT_ERROR, "Cannot unpack individual Library file, '%s'", li->name);
669         }
670 }