Merged changes in the trunk up to revision 50257.
[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 #include "BKE_utildefines.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                 }
89                 if (seek < 0) {
90                         seek = 0;
91                 }
92                 else if (seek > pf->size) {
93                         seek = pf->size;
94                 }
95                 pf->seek = seek;
96         }
97
98         return(oldseek);
99 }
100         
101 void rewindPackedFile(PackedFile *pf)
102 {
103         seekPackedFile(pf, 0, SEEK_SET);
104 }
105
106 int readPackedFile(PackedFile *pf, void *data, int size)
107
108         if ((pf != NULL) && (size >= 0) && (data != NULL)) {
109                 if (size + pf->seek > pf->size) {
110                         size = pf->size - pf->seek;
111                 }
112
113                 if (size > 0) {
114                         memcpy(data, ((char *) pf->data) + pf->seek, size);
115                 }
116                 else {
117                         size = 0;
118                 }
119
120                 pf->seek += size;
121         }
122         else {
123                 size = -1;
124         }
125
126         return(size);
127 }
128
129 int countPackedFiles(Main *bmain)
130 {
131         Image *ima;
132         VFont *vf;
133         bSound *sound;
134         int count = 0;
135         
136         /* let's check if there are packed files... */
137         for (ima = bmain->image.first; ima; ima = ima->id.next)
138                 if (ima->packedfile)
139                         count++;
140
141         for (vf = bmain->vfont.first; vf; vf = vf->id.next)
142                 if (vf->packedfile)
143                         count++;
144
145         for (sound = bmain->sound.first; sound; sound = sound->id.next)
146                 if (sound->packedfile)
147                         count++;
148
149         return count;
150 }
151
152 void freePackedFile(PackedFile *pf)
153 {
154         if (pf) {
155                 MEM_freeN(pf->data);
156                 MEM_freeN(pf);
157         }
158         else
159                 printf("freePackedFile: Trying to free a NULL pointer\n");
160 }
161
162 PackedFile *dupPackedFile(const PackedFile *pf_src)
163 {
164         PackedFile *pf_dst;
165
166         pf_dst       = MEM_dupallocN(pf_src);
167         pf_dst->data = MEM_dupallocN(pf_src->data);
168
169         return pf_dst;
170 }
171
172 PackedFile *newPackedFileMemory(void *mem, int memlen)
173 {
174         PackedFile *pf = MEM_callocN(sizeof(*pf), "PackedFile");
175         pf->data = mem;
176         pf->size = memlen;
177         
178         return pf;
179 }
180
181 PackedFile *newPackedFile(ReportList *reports, const char *filename, const char *basepath)
182 {
183         PackedFile *pf = NULL;
184         int file, filelen;
185         char name[FILE_MAX];
186         void *data;
187         
188         /* render result has no filename and can be ignored
189          * any other files with no name can be ignored too */
190         if (filename[0] == '\0')
191                 return NULL;
192
193         //XXX waitcursor(1);
194         
195         /* convert relative filenames to absolute filenames */
196
197         BLI_strncpy(name, filename, sizeof(name));
198         BLI_path_abs(name, basepath);
199
200         /* open the file
201          * and create a PackedFile structure */
202
203         file = BLI_open(name, O_BINARY | O_RDONLY, 0);
204         if (file <= 0) {
205                 BKE_reportf(reports, RPT_ERROR, "Unable to pack file, source path not found: \"%s\"", name);
206         }
207         else {
208                 filelen = BLI_file_descriptor_size(file);
209
210                 if (filelen == 0) {
211                         /* MEM_mallocN complains about MEM_mallocN(0, "bla");
212                          * we don't care.... */
213                         data = MEM_mallocN(1, "packFile");
214                 }
215                 else {
216                         data = MEM_mallocN(filelen, "packFile");
217                 }
218                 if (read(file, data, filelen) == filelen) {
219                         pf = newPackedFileMemory(data, filelen);
220                 }
221
222                 close(file);
223         }
224
225         //XXX waitcursor(0);
226                 
227         return (pf);
228 }
229
230 void packAll(Main *bmain, ReportList *reports)
231 {
232         Image *ima;
233         VFont *vfont;
234         bSound *sound;
235         
236         for (ima = bmain->image.first; ima; ima = ima->id.next) {
237                 if (ima->packedfile == NULL && ima->id.lib == NULL) {
238                         if (ima->source == IMA_SRC_FILE) {
239                                 ima->packedfile = newPackedFile(reports, ima->name, ID_BLEND_PATH(bmain, &ima->id));
240                         }
241                         else if (ELEM(ima->source, IMA_SRC_SEQUENCE, IMA_SRC_MOVIE)) {
242                                 BKE_reportf(reports, RPT_WARNING, "Image '%s' skipped, movies and image sequences not supported.", 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 tempfile. 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