Internal node links are now cached in a per-node list, instead of being generated...
[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_sound_types.h"
47 #include "DNA_vfont_types.h"
48 #include "DNA_packedFile_types.h"
49
50 #include "BLI_blenlib.h"
51 #include "BLI_utildefines.h"
52
53 #include "BKE_font.h"
54 #include "BKE_global.h"
55 #include "BKE_image.h"
56 #include "BKE_main.h"
57 #include "BKE_packedFile.h"
58 #include "BKE_report.h"
59 #include "BKE_sound.h"
60
61 #ifdef _WIN32
62 #define open _open
63 #define close _close
64 #define read _read
65 #define write _write
66 #endif
67
68
69 int seekPackedFile(PackedFile *pf, int offset, int whence)
70 {
71         int oldseek = -1, seek = 0;
72
73         if (pf) {
74                 oldseek = pf->seek;
75                 switch (whence) {
76                         case SEEK_CUR:
77                                 seek = oldseek + offset;
78                                 break;
79                         case SEEK_END:
80                                 seek = pf->size + offset;
81                                 break;
82                         case SEEK_SET:
83                                 seek = offset;
84                                 break;
85                         default:
86                                 oldseek = -1;
87                 }
88                 if (seek < 0) {
89                         seek = 0;
90                 }
91                 else if (seek > pf->size) {
92                         seek = pf->size;
93                 }
94                 pf->seek = seek;
95         }
96
97         return(oldseek);
98 }
99         
100 void rewindPackedFile(PackedFile *pf)
101 {
102         seekPackedFile(pf, 0, SEEK_SET);
103 }
104
105 int readPackedFile(PackedFile *pf, void *data, int size)
106
107         if ((pf != NULL) && (size >= 0) && (data != NULL)) {
108                 if (size + pf->seek > pf->size) {
109                         size = pf->size - pf->seek;
110                 }
111
112                 if (size > 0) {
113                         memcpy(data, ((char *) pf->data) + pf->seek, size);
114                 }
115                 else {
116                         size = 0;
117                 }
118
119                 pf->seek += size;
120         }
121         else {
122                 size = -1;
123         }
124
125         return(size);
126 }
127
128 int countPackedFiles(Main *bmain)
129 {
130         Image *ima;
131         VFont *vf;
132         bSound *sound;
133         int count = 0;
134         
135         /* let's check if there are packed files... */
136         for (ima = bmain->image.first; ima; ima = ima->id.next)
137                 if (ima->packedfile)
138                         count++;
139
140         for (vf = bmain->vfont.first; vf; vf = vf->id.next)
141                 if (vf->packedfile)
142                         count++;
143
144         for (sound = bmain->sound.first; sound; sound = sound->id.next)
145                 if (sound->packedfile)
146                         count++;
147
148         return count;
149 }
150
151 void freePackedFile(PackedFile *pf)
152 {
153         if (pf) {
154                 MEM_freeN(pf->data);
155                 MEM_freeN(pf);
156         }
157         else
158                 printf("freePackedFile: Trying to free a NULL pointer\n");
159 }
160
161 PackedFile *dupPackedFile(const PackedFile *pf_src)
162 {
163         PackedFile *pf_dst;
164
165         pf_dst       = MEM_dupallocN(pf_src);
166         pf_dst->data = MEM_dupallocN(pf_src->data);
167
168         return pf_dst;
169 }
170
171 PackedFile *newPackedFileMemory(void *mem, int memlen)
172 {
173         PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
174         pf->data = mem;
175         pf->size = memlen;
176         
177         return pf;
178 }
179
180 PackedFile *newPackedFile(ReportList *reports, const char *filename, const char *basepath)
181 {
182         PackedFile *pf = NULL;
183         int file, filelen;
184         char name[FILE_MAX];
185         void *data;
186         
187         /* render result has no filename and can be ignored
188          * any other files with no name can be ignored too */
189         if (filename[0] == '\0')
190                 return NULL;
191
192         //XXX waitcursor(1);
193         
194         /* convert relative filenames to absolute filenames */
195
196         BLI_strncpy(name, filename, sizeof(name));
197         BLI_path_abs(name, basepath);
198
199         /* open the file
200          * and create a PackedFile structure */
201
202         file = BLI_open(name, O_BINARY | O_RDONLY, 0);
203         if (file <= 0) {
204                 BKE_reportf(reports, RPT_ERROR, "Unable to pack file, source path '%s' not found", name);
205         }
206         else {
207                 filelen = BLI_file_descriptor_size(file);
208
209                 if (filelen == 0) {
210                         /* MEM_mallocN complains about MEM_mallocN(0, "bla");
211                          * we don't care.... */
212                         data = MEM_mallocN(1, "packFile");
213                 }
214                 else {
215                         data = MEM_mallocN(filelen, "packFile");
216                 }
217                 if (read(file, data, filelen) == filelen) {
218                         pf = newPackedFileMemory(data, filelen);
219                 }
220
221                 close(file);
222         }
223
224         //XXX waitcursor(0);
225                 
226         return (pf);
227 }
228
229 void packAll(Main *bmain, ReportList *reports)
230 {
231         Image *ima;
232         VFont *vfont;
233         bSound *sound;
234         
235         for (ima = bmain->image.first; ima; ima = ima->id.next) {
236                 if (ima->packedfile == NULL && ima->id.lib == NULL) {
237                         if (ima->source == IMA_SRC_FILE) {
238                                 ima->packedfile = newPackedFile(reports, ima->name, ID_BLEND_PATH(bmain, &ima->id));
239                         }
240                         else if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) {
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
251         for (sound = bmain->sound.first; sound; sound = sound->id.next)
252                 if (sound->packedfile == NULL && sound->id.lib == NULL)
253                         sound->packedfile = newPackedFile(reports, sound->name, bmain->name);
254 }
255
256
257 #if 0
258
259 // attempt to create a function that generates an unique filename
260 // this will work when all funtions in fileops.c understand relative filenames...
261
262 static char *find_new_name(char *name)
263 {
264         char tempname[FILE_MAX];
265         char *newname;
266         size_t len;
267         
268         if (fop_exists(name)) {
269                 for (number = 1; number <= 999; number++) {
270                         BLI_snprintf(tempname, sizeof(tempname), "%s.%03d", name, number);
271                         if (!fop_exists(tempname)) {
272                                 break;
273                         }
274                 }
275         }
276         len = strlen(tempname) + 1;
277         newname = MEM_mallocN(len, "find_new_name");
278         memcpy(newname, tempname, len * sizeof(char));
279         return newname;
280 }
281 #endif
282
283 int writePackedFile(ReportList *reports, const char *filename, PackedFile *pf, int guimode)
284 {
285         int file, number, remove_tmp = FALSE;
286         int ret_value = RET_OK;
287         char name[FILE_MAX];
288         char tempname[FILE_MAX];
289 /*      void *data; */
290         
291         if (guimode) {} //XXX  waitcursor(1);
292         
293         BLI_strncpy(name, filename, sizeof(name));
294         BLI_path_abs(name, G.main->name);
295         
296         if (BLI_exists(name)) {
297                 for (number = 1; number <= 999; number++) {
298                         BLI_snprintf(tempname, sizeof(tempname), "%s.%03d_", name, number);
299                         if (!BLI_exists(tempname)) {
300                                 if (BLI_copy(name, tempname) == RET_OK) {
301                                         remove_tmp = TRUE;
302                                 }
303                                 break;
304                         }
305                 }
306         }
307         
308         /* make sure the path to the file exists... */
309         BLI_make_existing_file(name);
310         
311         file = BLI_open(name, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666);
312         if (file >= 0) {
313                 if (write(file, pf->data, pf->size) != pf->size) {
314                         BKE_reportf(reports, RPT_ERROR, "Error writing file '%s'", name);
315                         ret_value = RET_ERROR;
316                 }
317                 close(file);
318         }
319         else {
320                 BKE_reportf(reports, RPT_ERROR, "Error creating file '%s'", name);
321                 ret_value = RET_ERROR;
322         }
323         
324         if (remove_tmp) {
325                 if (ret_value == RET_ERROR) {
326                         if (BLI_rename(tempname, name) != 0) {
327                                 BKE_reportf(reports, RPT_ERROR, "Error restoring temp file (check files '%s' '%s')", tempname, name);
328                         }
329                 }
330                 else {
331                         if (BLI_delete(tempname, 0, 0) != 0) {
332                                 BKE_reportf(reports, RPT_ERROR, "Error deleting '%s' (ignored)", tempname);
333                         }
334                 }
335         }
336         
337         if (guimode) {} //XXX waitcursor(0);
338
339         return (ret_value);
340 }
341         
342 /*
343  * This function compares a packed file to a 'real' file.
344  * It returns an integer indicating if:
345  *
346  * PF_EQUAL             - the packed file and original file are identical
347  * PF_DIFFERENT - the packed file and original file differ
348  * PF_NOFILE    - the original file doens't exist
349  */
350
351 int checkPackedFile(const char *filename, PackedFile *pf)
352 {
353         struct stat st;
354         int ret_val, i, len, file;
355         char buf[4096];
356         char name[FILE_MAX];
357         
358         BLI_strncpy(name, filename, sizeof(name));
359         BLI_path_abs(name, G.main->name);
360         
361         if (stat(name, &st)) {
362                 ret_val = PF_NOFILE;
363         }
364         else if (st.st_size != pf->size) {
365                 ret_val = PF_DIFFERS;
366         }
367         else {
368                 /* we'll have to compare the two... */
369
370                 file = BLI_open(name, O_BINARY | O_RDONLY, 0);
371                 if (file < 0) {
372                         ret_val = PF_NOFILE;
373                 }
374                 else {
375                         ret_val = PF_EQUAL;
376
377                         for (i = 0; i < pf->size; i += sizeof(buf)) {
378                                 len = pf->size - i;
379                                 if (len > sizeof(buf)) {
380                                         len = sizeof(buf);
381                                 }
382
383                                 if (read(file, buf, len) != len) {
384                                         /* read error ... */
385                                         ret_val = PF_DIFFERS;
386                                         break;
387                                 }
388                                 else {
389                                         if (memcmp(buf, ((char *)pf->data) + i, len)) {
390                                                 ret_val = PF_DIFFERS;
391                                                 break;
392                                         }
393                                 }
394                         }
395                         
396                         close(file);
397                 }
398         }
399         
400         return(ret_val);
401 }
402
403 /* unpackFile() looks at the existing files (abs_name, local_name) and a packed file.
404  *
405  * It returns a char *to the existing file name / new file name or NULL when
406  * there was an error or when the user decides to cancel the operation.
407  */
408
409 char *unpackFile(ReportList *reports, const char *abs_name, const char *local_name, PackedFile *pf, int how)
410 {
411         char *newname = NULL;
412         const char *temp = NULL;
413         
414         // char newabs[FILE_MAX];
415         // char newlocal[FILE_MAX];
416         
417         if (pf != NULL) {
418                 switch (how) {
419                         case -1:
420                         case PF_KEEP:
421                                 break;
422                         case PF_REMOVE:
423                                 temp = abs_name;
424                                 break;
425                         case PF_USE_LOCAL:
426                                 /* if file exists use it */
427                                 if (BLI_exists(local_name)) {
428                                         temp = local_name;
429                                         break;
430                                 }
431                         /* else fall through and create it */
432                         case PF_WRITE_LOCAL:
433                                 if (writePackedFile(reports, local_name, pf, 1) == RET_OK) {
434                                         temp = local_name;
435                                 }
436                                 break;
437                         case PF_USE_ORIGINAL:
438                                 /* if file exists use it */
439                                 if (BLI_exists(abs_name)) {
440                                         temp = abs_name;
441                                         break;
442                                 }
443                         /* else fall through and create it */
444                         case PF_WRITE_ORIGINAL:
445                                 if (writePackedFile(reports, abs_name, pf, 1) == RET_OK) {
446                                         temp = abs_name;
447                                 }
448                                 break;
449                         default:
450                                 printf("unpackFile: unknown return_value %d\n", how);
451                                 break;
452                 }
453                 
454                 if (temp) {
455                         newname = BLI_strdup(temp);
456                 }
457         }
458         
459         return newname;
460 }
461
462
463 int unpackVFont(ReportList *reports, VFont *vfont, int how)
464 {
465         char localname[FILE_MAX], fi[FILE_MAXFILE];
466         char *newname;
467         int ret_value = RET_ERROR;
468         
469         if (vfont != NULL) {
470                 BLI_strncpy(localname, vfont->name, sizeof(localname));
471                 BLI_splitdirstring(localname, fi);
472                 
473                 BLI_snprintf(localname, sizeof(localname), "//fonts/%s", fi);
474                 
475                 newname = unpackFile(reports, vfont->name, localname, vfont->packedfile, how);
476                 if (newname != NULL) {
477                         ret_value = RET_OK;
478                         freePackedFile(vfont->packedfile);
479                         vfont->packedfile = NULL;
480                         BLI_strncpy(vfont->name, newname, sizeof(vfont->name));
481                         MEM_freeN(newname);
482                 }
483         }
484         
485         return (ret_value);
486 }
487
488 int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how)
489 {
490         char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
491         char *newname;
492         int ret_value = RET_ERROR;
493
494         if (sound != NULL) {
495                 BLI_strncpy(localname, sound->name, sizeof(localname));
496                 BLI_splitdirstring(localname, fi);
497                 BLI_snprintf(localname, sizeof(localname), "//sounds/%s", fi);
498
499                 newname = unpackFile(reports, sound->name, localname, sound->packedfile, how);
500                 if (newname != NULL) {
501                         BLI_strncpy(sound->name, newname, sizeof(sound->name));
502                         MEM_freeN(newname);
503
504                         freePackedFile(sound->packedfile);
505                         sound->packedfile = NULL;
506
507                         sound_load(bmain, sound);
508
509                         ret_value = RET_OK;
510                 }
511         }
512         
513         return(ret_value);
514 }
515
516 int unpackImage(ReportList *reports, Image *ima, int how)
517 {
518         char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
519         char *newname;
520         int ret_value = RET_ERROR;
521         
522         if (ima != NULL && ima->name[0]) {
523                 BLI_strncpy(localname, ima->name, sizeof(localname));
524                 BLI_splitdirstring(localname, fi);
525                 BLI_snprintf(localname, sizeof(localname), "//textures/%s", fi);
526
527                 newname = unpackFile(reports, ima->name, localname, ima->packedfile, how);
528                 if (newname != NULL) {
529                         ret_value = RET_OK;
530                         freePackedFile(ima->packedfile);
531                         ima->packedfile = NULL;
532                         BLI_strncpy(ima->name, newname, sizeof(ima->name));
533                         MEM_freeN(newname);
534                         BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
535                 }
536         }
537         
538         return(ret_value);
539 }
540
541 void unpackAll(Main *bmain, ReportList *reports, int how)
542 {
543         Image *ima;
544         VFont *vf;
545         bSound *sound;
546
547         for (ima = bmain->image.first; ima; ima = ima->id.next)
548                 if (ima->packedfile)
549                         unpackImage(reports, ima, how);
550
551         for (vf = bmain->vfont.first; vf; vf = vf->id.next)
552                 if (vf->packedfile)
553                         unpackVFont(reports, vf, how);
554
555         for (sound = bmain->sound.first; sound; sound = sound->id.next)
556                 if (sound->packedfile)
557                         unpackSound(bmain, reports, sound, how);
558 }
559