NLA SoC: Merge from 2.5
[blender.git] / source / blender / blenkernel / intern / packedFile.c
1 /**
2  * blenkernel/packedFile.c - (cleaned up mar-01 nzc)
3  *
4  * $Id$
5  *
6  * ***** BEGIN GPL LICENSE BLOCK *****
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL LICENSE BLOCK *****
30  */
31
32 #include <stdio.h>
33 #include <fcntl.h>
34 #include <sys/stat.h>
35
36 #ifdef HAVE_CONFIG_H
37 #include <config.h>
38 #endif
39
40 #ifndef WIN32 
41 #include <unistd.h>
42 #else
43 #include <io.h>
44 #endif
45 #include <string.h>
46 #include "MEM_guardedalloc.h"
47
48 #include "DNA_image_types.h"
49 #include "DNA_sound_types.h"
50 #include "DNA_vfont_types.h"
51 #include "DNA_packedFile_types.h"
52 #include "DNA_scene_types.h"
53
54 #include "BLI_blenlib.h"
55
56 #include "BKE_utildefines.h"
57 #include "BKE_global.h"
58 #include "BKE_main.h"
59 #include "BKE_screen.h"
60 #include "BKE_sound.h"
61 #include "BKE_image.h"
62 #include "BKE_font.h"
63 #include "BKE_packedFile.h"
64 #include "BKE_report.h"
65
66 int seekPackedFile(PackedFile *pf, int offset, int whence)
67 {
68         int oldseek = -1, seek = 0;
69
70         if (pf) {
71                 oldseek = pf->seek;
72                 switch(whence) {
73                 case SEEK_CUR:
74                         seek = oldseek + offset;
75                         break;
76                 case SEEK_END:
77                         seek = pf->size + offset;
78                         break;
79                 case SEEK_SET:
80                         seek = offset;
81                         break;
82                 default:
83                         oldseek = -1;
84                 }
85                 if (seek < 0) {
86                         seek = 0;
87                 } else if (seek > pf->size) {
88                         seek = pf->size;
89                 }
90                 pf->seek = seek;
91         }
92
93         return(oldseek);
94 }
95         
96 void rewindPackedFile(PackedFile *pf)
97 {
98         seekPackedFile(pf, 0, SEEK_SET);
99 }
100
101 int readPackedFile(PackedFile *pf, void *data, int size)
102
103         if ((pf != NULL) && (size >= 0) && (data != NULL)) {
104                 if (size + pf->seek > pf->size) {
105                         size = pf->size - pf->seek;
106                 }
107
108                 if (size > 0) {
109                         memcpy(data, ((char *) pf->data) + pf->seek, size);
110                 } else {
111                         size = 0;
112                 }
113
114                 pf->seek += size;
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         bSample *sample;
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         if(samples)
139                 for(sample=samples->first; sample; sample=sample->id.next)
140                         if(sample->packedfile)
141                                 count++;
142
143         return count;
144 }
145
146 void freePackedFile(PackedFile *pf)
147 {
148         if(pf) {
149                 MEM_freeN(pf->data);
150                 MEM_freeN(pf);
151         }
152         else
153                 printf("freePackedFile: Trying to free a NULL pointer\n");
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, char *filename)
166 {
167         PackedFile *pf = NULL;
168         int file, filelen;
169         char name[FILE_MAXDIR+FILE_MAXFILE];
170         void *data;
171         
172         //XXX waitcursor(1);
173         
174         // convert relative filenames to absolute filenames
175         
176         strcpy(name, filename);
177         BLI_convertstringcode(name, G.sce);
178         
179         // open the file
180         // and create a PackedFile structure
181
182         file= open(name, O_BINARY|O_RDONLY);
183         if (file <= 0) {
184                 BKE_reportf(reports, RPT_ERROR, "Can't open file: %s", name);
185         } else {
186                 filelen = BLI_filesize(file);
187
188                 if (filelen == 0) {
189                         // MEM_mallocN complains about MEM_mallocN(0, "bla");
190                         // we don't care....
191                         data = MEM_mallocN(1, "packFile");
192                 } else {
193                         data = MEM_mallocN(filelen, "packFile");
194                 }
195                 if (read(file, data, filelen) == filelen) {
196                         pf = newPackedFileMemory(data, filelen);
197                 }
198
199                 close(file);
200         }
201
202         //XXX waitcursor(0);
203                 
204         return (pf);
205 }
206
207 void packAll(Main *bmain, ReportList *reports)
208 {
209         Image *ima;
210         VFont *vf;
211         bSample *sample;
212         
213         for(ima=bmain->image.first; ima; ima=ima->id.next)
214                 if(ima->packedfile == NULL)
215                         ima->packedfile = newPackedFile(reports, ima->name);
216
217         for(vf=bmain->vfont.first; vf; vf=vf->id.next)
218                 if(vf->packedfile == NULL)
219                         vf->packedfile = newPackedFile(reports, vf->name);
220
221         if(samples)
222                 for(sample=samples->first; sample; sample=sample->id.next)
223                         if(sample->packedfile == NULL)
224                                 sound_set_packedfile(sample, newPackedFile(reports, sample->name));
225 }
226
227
228 /*
229
230 // attempt to create a function that generates an unique filename
231 // this will work when all funtions in fileops.c understand relative filenames...
232
233 char *find_new_name(char *name)
234 {
235         char tempname[FILE_MAXDIR + FILE_MAXFILE];
236         char *newname;
237         
238         if (fop_exists(name)) {
239                 for (number = 1; number <= 999; number++) {
240                         sprintf(tempname, "%s.%03d", name, number);
241                         if (! fop_exists(tempname)) {
242                                 break;
243                         }
244                 }
245         }
246         
247         newname = mallocN(strlen(tempname) + 1, "find_new_name");
248         strcpy(newname, tempname);
249         
250         return(newname);
251 }
252         
253 */
254
255 int writePackedFile(ReportList *reports, char *filename, PackedFile *pf, int guimode)
256 {
257         int file, number, remove_tmp = FALSE;
258         int ret_value = RET_OK;
259         char name[FILE_MAXDIR + FILE_MAXFILE];
260         char tempname[FILE_MAXDIR + FILE_MAXFILE];
261 /*      void *data; */
262         
263         if (guimode); //XXX  waitcursor(1);
264         
265         strcpy(name, filename);
266         BLI_convertstringcode(name, G.sce);
267         
268         if (BLI_exists(name)) {
269                 for (number = 1; number <= 999; number++) {
270                         sprintf(tempname, "%s.%03d_", name, number);
271                         if (! BLI_exists(tempname)) {
272                                 if (BLI_copy_fileops(name, tempname) == RET_OK) {
273                                         remove_tmp = TRUE;
274                                 }
275                                 break;
276                         }
277                 }
278         }
279         
280         // make sure the path to the file exists...
281         BLI_make_existing_file(name);
282         
283         file = open(name, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666);
284         if (file >= 0) {
285                 if (write(file, pf->data, pf->size) != pf->size) {
286                         BKE_reportf(reports, RPT_ERROR, "Error writing file: %s", name);
287                         ret_value = RET_ERROR;
288                 }
289                 close(file);
290         } else {
291                 BKE_reportf(reports, RPT_ERROR, "Error creating file: %s", name);
292                 ret_value = RET_ERROR;
293         }
294         
295         if (remove_tmp) {
296                 if (ret_value == RET_ERROR) {
297                         if (BLI_rename(tempname, name) != 0) {
298                                 BKE_reportf(reports, RPT_ERROR, "Error restoring tempfile. Check files: '%s' '%s'", tempname, name);
299                         }
300                 } else {
301                         if (BLI_delete(tempname, 0, 0) != 0) {
302                                 BKE_reportf(reports, RPT_ERROR, "Error deleting '%s' (ignored)", tempname);
303                         }
304                 }
305         }
306         
307         if(guimode); //XXX waitcursor(0);
308
309         return (ret_value);
310 }
311         
312 /* 
313
314 This function compares a packed file to a 'real' file.
315 It returns an integer indicating if:
316
317 PF_EQUAL                - the packed file and original file are identical
318 PF_DIFFERENT    - the packed file and original file differ
319 PF_NOFILE               - the original file doens't exist
320
321 */
322
323 int checkPackedFile(char *filename, PackedFile *pf)
324 {
325         struct stat st;
326         int ret_val, i, len, file;
327         char buf[4096];
328         char name[FILE_MAXDIR + FILE_MAXFILE];
329         
330         strcpy(name, filename);
331         BLI_convertstringcode(name, G.sce);
332         
333         if (stat(name, &st)) {
334                 ret_val = PF_NOFILE;
335         } else if (st.st_size != pf->size) {
336                 ret_val = PF_DIFFERS;
337         } else {
338                 // we'll have to compare the two...
339                 
340                 file = open(name, O_BINARY | O_RDONLY);
341                 if (file < 0) {
342                         ret_val = PF_NOFILE;
343                 } else {
344                         ret_val = PF_EQUAL;
345                         
346                         for (i = 0; i < pf->size; i += sizeof(buf)) {
347                                 len = pf->size - i;
348                                 if (len > sizeof(buf)) {
349                                         len = sizeof(buf);
350                                 }
351                                 
352                                 if (read(file, buf, len) != len) {
353                                         // read error ...
354                                         ret_val = PF_DIFFERS;
355                                         break;
356                                 } else {
357                                         if (memcmp(buf, ((char *)pf->data) + i, len)) {
358                                                 ret_val = PF_DIFFERS;
359                                                 break;
360                                         }
361                                 }
362                         }
363                 }
364         }
365         
366         return(ret_val);
367 }
368
369 /*
370
371    unpackFile() looks at the existing files (abs_name, local_name) and a packed file.
372
373 It returns a char *to the existing file name / new file name or NULL when
374 there was an error or when the user desides to cancel the operation.
375
376 */
377
378 char *unpackFile(ReportList *reports, char *abs_name, char *local_name, PackedFile *pf, int how)
379 {
380         char menu[6 *(FILE_MAXDIR + FILE_MAXFILE + 100)];
381         char line[FILE_MAXDIR + FILE_MAXFILE + 100];
382         char *newname = NULL, *temp = NULL;
383         
384         // char newabs[FILE_MAXDIR + FILE_MAXFILE];
385         // char newlocal[FILE_MAXDIR + FILE_MAXFILE];
386         
387         if (pf != NULL) {
388                 switch (how) {
389                         case -1:
390                         case PF_KEEP:
391                                 break;
392                         case PF_REMOVE:
393                                 temp= abs_name;
394                                 break;
395                         case PF_USE_LOCAL:
396                                 // if file exists use it
397                                 if (BLI_exists(local_name)) {
398                                         temp = local_name;
399                                         break;
400                                 }
401                                 // else fall through and create it
402                         case PF_WRITE_LOCAL:
403                                 if (writePackedFile(reports, local_name, pf, 1) == RET_OK) {
404                                         temp = local_name;
405                                 }
406                                 break;
407                         case PF_USE_ORIGINAL:
408                                 // if file exists use it
409                                 if (BLI_exists(abs_name)) {
410                                         temp = abs_name;
411                                         break;
412                                 }
413                                 // else fall through and create it
414                         case PF_WRITE_ORIGINAL:
415                                 if (writePackedFile(reports, abs_name, pf, 1) == RET_OK) {
416                                         temp = abs_name;
417                                 }
418                                 break;
419                         default:
420                                 printf("unpackFile: unknown return_value %d\n", how);
421                                 break;
422                 }
423                 
424                 if (temp) {
425                         newname = MEM_mallocN(strlen(temp) + 1, "unpack_file newname");
426                         strcpy(newname, temp);
427                 }
428         }
429         
430         return (newname);
431 }
432
433
434 int unpackVFont(ReportList *reports, VFont *vfont, int how)
435 {
436         char localname[FILE_MAXDIR + FILE_MAXFILE], fi[FILE_MAXFILE];
437         char *newname;
438         int ret_value = RET_ERROR;
439         
440         if (vfont != NULL) {
441                 strcpy(localname, vfont->name);
442                 BLI_splitdirstring(localname, fi);
443                 
444                 sprintf(localname, "//fonts/%s", fi);
445                 
446                 newname = unpackFile(reports, vfont->name, localname, vfont->packedfile, how);
447                 if (newname != NULL) {
448                         ret_value = RET_OK;
449                         freePackedFile(vfont->packedfile);
450                         vfont->packedfile = 0;
451                         strcpy(vfont->name, newname);
452                         MEM_freeN(newname);
453                 }
454         }
455         
456         return (ret_value);
457 }
458
459 int unpackSample(ReportList *reports, bSample *sample, int how)
460 {
461         char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
462         char *newname;
463         int ret_value = RET_ERROR;
464         PackedFile *pf;
465         
466         if (sample != NULL) {
467                 strcpy(localname, sample->name);
468                 BLI_splitdirstring(localname, fi);
469                 sprintf(localname, "//samples/%s", fi);
470                 
471                 newname = unpackFile(reports, sample->name, localname, sample->packedfile, how);
472                 if (newname != NULL) {
473                         strcpy(sample->name, newname);
474                         MEM_freeN(newname);
475
476                         pf = sample->packedfile;
477                         // because samples and sounds can point to the
478                         // same packedfile we have to check them all
479                         sound_set_packedfile(sample, NULL);
480                         freePackedFile(pf);
481
482                         ret_value = RET_OK;
483                 }
484         }
485         
486         return(ret_value);
487 }
488
489 int unpackImage(ReportList *reports, Image *ima, int how)
490 {
491         char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
492         char *newname;
493         int ret_value = RET_ERROR;
494         
495         if (ima != NULL) {
496                 strcpy(localname, ima->name);
497                 BLI_splitdirstring(localname, fi);
498                 sprintf(localname, "//textures/%s", fi);
499                         
500                 newname = unpackFile(reports, ima->name, localname, ima->packedfile, how);
501                 if (newname != NULL) {
502                         ret_value = RET_OK;
503                         freePackedFile(ima->packedfile);
504                         ima->packedfile = NULL;
505                         strcpy(ima->name, newname);
506                         MEM_freeN(newname);
507                         BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
508                 }
509         }
510         
511         return(ret_value);
512 }
513
514 void unpackAll(Main *bmain, ReportList *reports, int how)
515 {
516         Image *ima;
517         VFont *vf;
518         bSample *sample;
519
520         for(ima=bmain->image.first; ima; ima=ima->id.next)
521                 if(ima->packedfile)
522                         unpackImage(reports, ima, how);
523
524         for(vf=bmain->vfont.first; vf; vf=vf->id.next)
525                 if(vf->packedfile)
526                         unpackVFont(reports, vf, how);
527
528         if(samples)
529                 for(sample=samples->first; sample; sample=sample->id.next)
530                         if(sample->packedfile)
531                                 unpackSample(reports, sample, how);
532 }
533