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