Merging r50265 through r50373 from trunk into soc-2011-tomato
[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 not found: \"%s\"", 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.", ima->id.name + 2);
242                         }
243                 }
244         }
245
246         for (vfont = bmain->vfont.first; vfont; vfont = vfont->id.next)
247                 if (vfont->packedfile == NULL && vfont->id.lib == NULL && BKE_vfont_is_builtin(vfont) == FALSE)
248                         vfont->packedfile = newPackedFile(reports, vfont->name, bmain->name);
249
250         for (sound = bmain->sound.first; sound; sound = sound->id.next)
251                 if (sound->packedfile == NULL && sound->id.lib == NULL)
252                         sound->packedfile = newPackedFile(reports, sound->name, bmain->name);
253 }
254
255
256 #if 0
257
258 // attempt to create a function that generates an unique filename
259 // this will work when all funtions in fileops.c understand relative filenames...
260
261 static char *find_new_name(char *name)
262 {
263         char tempname[FILE_MAX];
264         char *newname;
265         size_t len;
266         
267         if (fop_exists(name)) {
268                 for (number = 1; number <= 999; number++) {
269                         BLI_snprintf(tempname, sizeof(tempname), "%s.%03d", name, number);
270                         if (!fop_exists(tempname)) {
271                                 break;
272                         }
273                 }
274         }
275         len = strlen(tempname) + 1;
276         newname = MEM_mallocN(len, "find_new_name");
277         memcpy(newname, tempname, len * sizeof(char));
278         return newname;
279 }
280 #endif
281
282 int writePackedFile(ReportList *reports, const char *filename, PackedFile *pf, int guimode)
283 {
284         int file, number, remove_tmp = FALSE;
285         int ret_value = RET_OK;
286         char name[FILE_MAX];
287         char tempname[FILE_MAX];
288 /*      void *data; */
289         
290         if (guimode) {} //XXX  waitcursor(1);
291         
292         BLI_strncpy(name, filename, sizeof(name));
293         BLI_path_abs(name, G.main->name);
294         
295         if (BLI_exists(name)) {
296                 for (number = 1; number <= 999; number++) {
297                         BLI_snprintf(tempname, sizeof(tempname), "%s.%03d_", name, number);
298                         if (!BLI_exists(tempname)) {
299                                 if (BLI_copy(name, tempname) == RET_OK) {
300                                         remove_tmp = TRUE;
301                                 }
302                                 break;
303                         }
304                 }
305         }
306         
307         /* make sure the path to the file exists... */
308         BLI_make_existing_file(name);
309         
310         file = BLI_open(name, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666);
311         if (file >= 0) {
312                 if (write(file, pf->data, pf->size) != pf->size) {
313                         BKE_reportf(reports, RPT_ERROR, "Error writing file: %s", name);
314                         ret_value = RET_ERROR;
315                 }
316                 close(file);
317         }
318         else {
319                 BKE_reportf(reports, RPT_ERROR, "Error creating file: %s", name);
320                 ret_value = RET_ERROR;
321         }
322         
323         if (remove_tmp) {
324                 if (ret_value == RET_ERROR) {
325                         if (BLI_rename(tempname, name) != 0) {
326                                 BKE_reportf(reports, RPT_ERROR, "Error restoring tempfile. Check files: '%s' '%s'", tempname, name);
327                         }
328                 }
329                 else {
330                         if (BLI_delete(tempname, 0, 0) != 0) {
331                                 BKE_reportf(reports, RPT_ERROR, "Error deleting '%s' (ignored)", tempname);
332                         }
333                 }
334         }
335         
336         if (guimode) {} //XXX waitcursor(0);
337
338         return (ret_value);
339 }
340         
341 /*
342  * This function compares a packed file to a 'real' file.
343  * It returns an integer indicating if:
344  *
345  * PF_EQUAL             - the packed file and original file are identical
346  * PF_DIFFERENT - the packed file and original file differ
347  * PF_NOFILE    - the original file doens't exist
348  */
349
350 int checkPackedFile(const char *filename, PackedFile *pf)
351 {
352         struct stat st;
353         int ret_val, i, len, file;
354         char buf[4096];
355         char name[FILE_MAX];
356         
357         BLI_strncpy(name, filename, sizeof(name));
358         BLI_path_abs(name, G.main->name);
359         
360         if (stat(name, &st)) {
361                 ret_val = PF_NOFILE;
362         }
363         else if (st.st_size != pf->size) {
364                 ret_val = PF_DIFFERS;
365         }
366         else {
367                 /* we'll have to compare the two... */
368
369                 file = BLI_open(name, O_BINARY | O_RDONLY, 0);
370                 if (file < 0) {
371                         ret_val = PF_NOFILE;
372                 }
373                 else {
374                         ret_val = PF_EQUAL;
375
376                         for (i = 0; i < pf->size; i += sizeof(buf)) {
377                                 len = pf->size - i;
378                                 if (len > sizeof(buf)) {
379                                         len = sizeof(buf);
380                                 }
381
382                                 if (read(file, buf, len) != len) {
383                                         /* read error ... */
384                                         ret_val = PF_DIFFERS;
385                                         break;
386                                 }
387                                 else {
388                                         if (memcmp(buf, ((char *)pf->data) + i, len)) {
389                                                 ret_val = PF_DIFFERS;
390                                                 break;
391                                         }
392                                 }
393                         }
394                         
395                         close(file);
396                 }
397         }
398         
399         return(ret_val);
400 }
401
402 /* unpackFile() looks at the existing files (abs_name, local_name) and a packed file.
403  *
404  * It returns a char *to the existing file name / new file name or NULL when
405  * there was an error or when the user decides to cancel the operation.
406  */
407
408 char *unpackFile(ReportList *reports, const char *abs_name, const char *local_name, PackedFile *pf, int how)
409 {
410         char *newname = NULL;
411         const char *temp = NULL;
412         
413         // char newabs[FILE_MAX];
414         // char newlocal[FILE_MAX];
415         
416         if (pf != NULL) {
417                 switch (how) {
418                         case -1:
419                         case PF_KEEP:
420                                 break;
421                         case PF_REMOVE:
422                                 temp = abs_name;
423                                 break;
424                         case PF_USE_LOCAL:
425                                 /* if file exists use it */
426                                 if (BLI_exists(local_name)) {
427                                         temp = local_name;
428                                         break;
429                                 }
430                         /* else fall through and create it */
431                         case PF_WRITE_LOCAL:
432                                 if (writePackedFile(reports, local_name, pf, 1) == RET_OK) {
433                                         temp = local_name;
434                                 }
435                                 break;
436                         case PF_USE_ORIGINAL:
437                                 /* if file exists use it */
438                                 if (BLI_exists(abs_name)) {
439                                         temp = abs_name;
440                                         break;
441                                 }
442                         /* else fall through and create it */
443                         case PF_WRITE_ORIGINAL:
444                                 if (writePackedFile(reports, abs_name, pf, 1) == RET_OK) {
445                                         temp = abs_name;
446                                 }
447                                 break;
448                         default:
449                                 printf("unpackFile: unknown return_value %d\n", how);
450                                 break;
451                 }
452                 
453                 if (temp) {
454                         newname = BLI_strdup(temp);
455                 }
456         }
457         
458         return newname;
459 }
460
461
462 int unpackVFont(ReportList *reports, VFont *vfont, int how)
463 {
464         char localname[FILE_MAX], fi[FILE_MAXFILE];
465         char *newname;
466         int ret_value = RET_ERROR;
467         
468         if (vfont != NULL) {
469                 BLI_strncpy(localname, vfont->name, sizeof(localname));
470                 BLI_splitdirstring(localname, fi);
471                 
472                 BLI_snprintf(localname, sizeof(localname), "//fonts/%s", fi);
473                 
474                 newname = unpackFile(reports, vfont->name, localname, vfont->packedfile, how);
475                 if (newname != NULL) {
476                         ret_value = RET_OK;
477                         freePackedFile(vfont->packedfile);
478                         vfont->packedfile = NULL;
479                         BLI_strncpy(vfont->name, newname, sizeof(vfont->name));
480                         MEM_freeN(newname);
481                 }
482         }
483         
484         return (ret_value);
485 }
486
487 int unpackSound(Main *bmain, ReportList *reports, bSound *sound, int how)
488 {
489         char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
490         char *newname;
491         int ret_value = RET_ERROR;
492
493         if (sound != NULL) {
494                 BLI_strncpy(localname, sound->name, sizeof(localname));
495                 BLI_splitdirstring(localname, fi);
496                 BLI_snprintf(localname, sizeof(localname), "//sounds/%s", fi);
497
498                 newname = unpackFile(reports, sound->name, localname, sound->packedfile, how);
499                 if (newname != NULL) {
500                         BLI_strncpy(sound->name, newname, sizeof(sound->name));
501                         MEM_freeN(newname);
502
503                         freePackedFile(sound->packedfile);
504                         sound->packedfile = NULL;
505
506                         sound_load(bmain, sound);
507
508                         ret_value = RET_OK;
509                 }
510         }
511         
512         return(ret_value);
513 }
514
515 int unpackImage(ReportList *reports, Image *ima, int how)
516 {
517         char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
518         char *newname;
519         int ret_value = RET_ERROR;
520         
521         if (ima != NULL && ima->name[0]) {
522                 BLI_strncpy(localname, ima->name, sizeof(localname));
523                 BLI_splitdirstring(localname, fi);
524                 BLI_snprintf(localname, sizeof(localname), "//textures/%s", fi);
525
526                 newname = unpackFile(reports, ima->name, localname, ima->packedfile, how);
527                 if (newname != NULL) {
528                         ret_value = RET_OK;
529                         freePackedFile(ima->packedfile);
530                         ima->packedfile = NULL;
531                         BLI_strncpy(ima->name, newname, sizeof(ima->name));
532                         MEM_freeN(newname);
533                         BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
534                 }
535         }
536         
537         return(ret_value);
538 }
539
540 void unpackAll(Main *bmain, ReportList *reports, int how)
541 {
542         Image *ima;
543         VFont *vf;
544         bSound *sound;
545
546         for (ima = bmain->image.first; ima; ima = ima->id.next)
547                 if (ima->packedfile)
548                         unpackImage(reports, ima, how);
549
550         for (vf = bmain->vfont.first; vf; vf = vf->id.next)
551                 if (vf->packedfile)
552                         unpackVFont(reports, vf, how);
553
554         for (sound = bmain->sound.first; sound; sound = sound->id.next)
555                 if (sound->packedfile)
556                         unpackSound(bmain, reports, sound, how);
557 }
558