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