Changed frame numbering to only alter hashes if they are in the filename (not the...
[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_bad_level_calls.h" /* <- waitcursor */
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()
123 {
124         int count = 0;
125         Image *ima;
126         VFont *vf;
127         bSample *sample;
128         
129         // let's check if there are packed files...
130         ima = G.main->image.first;
131         while (ima) {
132                 if (ima->packedfile) {
133                         count++;
134                 }
135                 ima= ima->id.next;
136         }
137
138         vf = G.main->vfont.first;
139         while (vf) {
140                 if (vf->packedfile) {
141                         count++;
142                 }
143                 vf = vf->id.next;
144         }
145
146         sample = samples->first;
147         while (sample) {
148                 if (sample->packedfile) {
149                         count++;
150                 }
151                 sample = sample->id.next;
152         }
153
154         return(count);
155 }
156
157 void freePackedFile(PackedFile * pf)
158 {
159         if (pf) {
160                 MEM_freeN(pf->data);
161                 MEM_freeN(pf);
162         } else {
163                 printf("freePackedFile: Trying to free a NULL pointer\n");
164         }
165 }
166         
167 PackedFile * newPackedFileMemory(void *mem, int memlen)
168 {
169         PackedFile * pf = MEM_callocN(sizeof(*pf), "PackedFile");
170         pf->data = mem;
171         pf->size = memlen;
172         
173         return pf;
174 }
175
176 PackedFile * newPackedFile(char * filename)
177 {
178         PackedFile * pf = NULL;
179         int file, filelen;
180         char name[FILE_MAXDIR+FILE_MAXFILE];
181         void * data;
182         
183         waitcursor(1);
184         
185         // convert relative filenames to absolute filenames
186         
187         strcpy(name, filename);
188         BLI_convertstringcode(name, G.sce);
189         
190         // open the file
191         // and create a PackedFile structure
192
193         file= open(name, O_BINARY|O_RDONLY);
194         if (file <= 0) {
195                 // error("Can't open file: %s", name);
196         } else {
197                 filelen = BLI_filesize(file);
198
199                 if (filelen == 0) {
200                         // MEM_mallocN complains about MEM_mallocN(0, "bla");
201                         // we don't care....
202                         data = MEM_mallocN(1, "packFile");
203                 } else {
204                         data = MEM_mallocN(filelen, "packFile");
205                 }
206                 if (read(file, data, filelen) == filelen) {
207                         pf = newPackedFileMemory(data, filelen);
208                 }
209
210                 close(file);
211         }
212
213         waitcursor(0);
214                 
215         return (pf);
216 }
217
218 void packAll()
219 {
220         Image *ima;
221         VFont *vf;
222         bSample *sample;
223         
224         ima = G.main->image.first;
225         while (ima) {
226                 if (ima->packedfile == NULL) {
227                         ima->packedfile = newPackedFile(ima->name);
228                 }
229                 ima= ima->id.next;
230         }
231         
232         vf = G.main->vfont.first;
233         while (vf) {
234                 if (vf->packedfile == NULL) {
235                         vf->packedfile = newPackedFile(vf->name);
236                 }
237                 vf = vf->id.next;
238         }
239
240
241         sample = samples->first;
242         while (sample) {
243                 if (sample->packedfile == NULL) {
244                         sound_set_packedfile(sample, newPackedFile(sample->name));
245                 }
246                 sample = sample->id.next;
247         }
248 }
249
250
251 /*
252
253 // attempt to create a function that generates an unique filename
254 // this will work when all funtions in fileops.c understand relative filenames...
255
256 char * find_new_name(char * name)
257 {
258         char tempname[FILE_MAXDIR + FILE_MAXFILE];
259         char * newname;
260         
261         if (fop_exists(name)) {
262                 for (number = 1; number <= 999; number++) {
263                         sprintf(tempname, "%s.%03d", name, number);
264                         if (! fop_exists(tempname)) {
265                                 break;
266                         }
267                 }
268         }
269         
270         newname = mallocN(strlen(tempname) + 1, "find_new_name");
271         strcpy(newname, tempname);
272         
273         return(newname);
274 }
275         
276 */
277
278 int writePackedFile(char * filename, PackedFile *pf, int guimode)
279 {
280         int file, number, remove_tmp = FALSE;
281         int ret_value = RET_OK;
282         char name[FILE_MAXDIR + FILE_MAXFILE];
283         char tempname[FILE_MAXDIR + FILE_MAXFILE];
284 /*      void * data; */
285         
286         if (guimode) waitcursor(1);
287         
288         strcpy(name, filename);
289         BLI_convertstringcode(name, G.sce);
290         
291         if (BLI_exists(name)) {
292                 for (number = 1; number <= 999; number++) {
293                         sprintf(tempname, "%s.%03d_", name, number);
294                         if (! BLI_exists(tempname)) {
295                                 if (BLI_copy_fileops(name, tempname) == RET_OK) {
296                                         remove_tmp = TRUE;
297                                 }
298                                 break;
299                         }
300                 }
301         }
302         
303         // make sure the path to the file exists...
304         BLI_make_existing_file(name);
305         
306         file = open(name, O_BINARY + O_WRONLY + O_CREAT + O_TRUNC, 0666);
307         if (file >= 0) {
308                 if (write(file, pf->data, pf->size) != pf->size) {
309                         if(guimode) error("Error writing file: %s", name);
310                         ret_value = RET_ERROR;
311                 }
312                 close(file);
313         } else {
314                 if(guimode) error("Error creating file: %s", name);
315                 ret_value = RET_ERROR;
316         }
317         
318         if (remove_tmp) {
319                 if (ret_value == RET_ERROR) {
320                         if (BLI_rename(tempname, name) != 0) {
321                                 if(guimode) error("Error restoring tempfile. Check files: '%s' '%s'", tempname, name);
322                         }
323                 } else {
324                         if (BLI_delete(tempname, 0, 0) != 0) {
325                                 if(guimode) error("Error deleting '%s' (ignored)");
326                         }
327                 }
328         }
329         
330         if(guimode) waitcursor(0);
331
332         return (ret_value);
333 }
334         
335 /* 
336
337 This function compares a packed file to a 'real' file.
338 It returns an integer indicating if:
339
340 PF_EQUAL                - the packed file and original file are identical
341 PF_DIFFERENT    - the packed file and original file differ
342 PF_NOFILE               - the original file doens't exist
343
344 */
345
346 int checkPackedFile(char * filename, PackedFile * pf)
347 {
348         struct stat st;
349         int ret_val, i, len, file;
350         char buf[4096];
351         char name[FILE_MAXDIR + FILE_MAXFILE];
352         
353         strcpy(name, filename);
354         BLI_convertstringcode(name, G.sce);
355         
356         if (stat(name, &st)) {
357                 ret_val = PF_NOFILE;
358         } else if (st.st_size != pf->size) {
359                 ret_val = PF_DIFFERS;
360         } else {
361                 // we'll have to compare the two...
362                 
363                 file = open(name, O_BINARY | O_RDONLY);
364                 if (file < 0) {
365                         ret_val = PF_NOFILE;
366                 } else {
367                         ret_val = PF_EQUAL;
368                         
369                         for (i = 0; i < pf->size; i += sizeof(buf)) {
370                                 len = pf->size - i;
371                                 if (len > sizeof(buf)) {
372                                         len = sizeof(buf);
373                                 }
374                                 
375                                 if (read(file, buf, len) != len) {
376                                         // read error ...
377                                         ret_val = PF_DIFFERS;
378                                         break;
379                                 } else {
380                                         if (memcmp(buf, ((char *)pf->data) + i, len)) {
381                                                 ret_val = PF_DIFFERS;
382                                                 break;
383                                         }
384                                 }
385                         }
386                 }
387         }
388         
389         return(ret_val);
390 }
391
392 /*
393
394 unpackFile() looks at the existing files (abs_name, local_name) and a packed file.
395 If how == PF_ASK it offers the user a couple of options what to do with the packed file.
396
397 It returns a char * to the existing file name / new file name or NULL when
398 there was an error or when the user desides to cancel the operation.
399
400 */
401
402 char *unpackFile(char * abs_name, char * local_name, PackedFile * pf, int how)
403 {
404         char menu[6 * (FILE_MAXDIR + FILE_MAXFILE + 100)];
405         char line[FILE_MAXDIR + FILE_MAXFILE + 100];
406         char * newname = NULL, * temp = NULL;
407         
408         // char newabs[FILE_MAXDIR + FILE_MAXFILE];
409         // char newlocal[FILE_MAXDIR + FILE_MAXFILE];
410         
411         if (pf != NULL) {
412                 if (how == PF_ASK) {
413                         sprintf(menu, "UnPack file%%t|Remove Pack %%x%d", PF_REMOVE);
414                         
415                         if (strcmp(abs_name, local_name)) {
416                                 switch (checkPackedFile(local_name, pf)) {
417                                         case PF_NOFILE:
418                                                 sprintf(line, "|Create %s%%x%d", local_name, PF_WRITE_LOCAL);
419                                                 strcat(menu, line);
420                                                 break;
421                                         case PF_EQUAL:
422                                                 sprintf(line, "|Use %s (identical)%%x%d", local_name, PF_USE_LOCAL);
423                                                 strcat(menu, line);
424                                                 break;
425                                         case PF_DIFFERS:
426                                                 sprintf(line, "|Use %s (differs)%%x%d", local_name, PF_USE_LOCAL);
427                                                 strcat(menu, line);
428                                                 sprintf(line, "|Overwrite %s%%x%d", local_name, PF_WRITE_LOCAL);
429                                                 strcat(menu, line);
430                                                 break;
431                                 }
432                                 // sprintf(line, "|%%x%d", PF_INVALID);
433                                 // strcat(menu, line);
434                         }
435                         
436                         switch (checkPackedFile(abs_name, pf)) {
437                                 case PF_NOFILE:
438                                         sprintf(line, "|Create %s%%x%d", abs_name, PF_WRITE_ORIGINAL);
439                                         strcat(menu, line);
440                                         break;
441                                 case PF_EQUAL:
442                                         sprintf(line, "|Use %s (identical)%%x%d", abs_name, PF_USE_ORIGINAL);
443                                         strcat(menu, line);
444                                         break;
445                                 case PF_DIFFERS:
446                                         sprintf(line, "|Use %s (differs)%%x%d", abs_name, PF_USE_ORIGINAL);
447                                         strcat(menu, line);
448                                         sprintf(line, "|Overwrite %s%%x%d", abs_name, PF_WRITE_ORIGINAL);
449                                         strcat(menu, line);
450                                         break;
451                         }
452                         
453                         how = pupmenu(menu);
454                 }
455                 
456                 switch (how) {
457                         case -1:
458                         case PF_KEEP:
459                                 break;
460                         case PF_REMOVE:
461                                 temp= abs_name;
462                                 break;
463                         case PF_USE_LOCAL:
464                                 // if file exists use it
465                                 if (BLI_exists(local_name)) {
466                                         temp = local_name;
467                                         break;
468                                 }
469                                 // else fall through and create it
470                         case PF_WRITE_LOCAL:
471                                 if (writePackedFile(local_name, pf, 1) == RET_OK) {
472                                         temp = local_name;
473                                 }
474                                 break;
475                         case PF_USE_ORIGINAL:
476                                 // if file exists use it
477                                 if (BLI_exists(abs_name)) {
478                                         temp = abs_name;
479                                         break;
480                                 }
481                                 // else fall through and create it
482                         case PF_WRITE_ORIGINAL:
483                                 if (writePackedFile(abs_name, pf, 1) == RET_OK) {
484                                         temp = abs_name;
485                                 }
486                                 break;
487                         default:
488                                 printf("unpackFile: unknown return_value %d\n", how);
489                                 break;
490                 }
491                 
492                 if (temp) {
493                         newname = MEM_mallocN(strlen(temp) + 1, "unpack_file newname");
494                         strcpy(newname, temp);
495                 }
496         }
497         
498         return (newname);
499 }
500
501
502 int unpackVFont(VFont * vfont, int how)
503 {
504         char localname[FILE_MAXDIR + FILE_MAXFILE], fi[FILE_MAXFILE];
505         char * newname;
506         int ret_value = RET_ERROR;
507         
508         if (vfont != NULL) {
509                 strcpy(localname, vfont->name);
510                 BLI_splitdirstring(localname, fi);
511                 
512                 sprintf(localname, "//fonts/%s", fi);
513                 
514                 newname = unpackFile(vfont->name, localname, vfont->packedfile, how);
515                 if (newname != NULL) {
516                         ret_value = RET_OK;
517                         freePackedFile(vfont->packedfile);
518                         vfont->packedfile = 0;
519                         strcpy(vfont->name, newname);
520                         MEM_freeN(newname);
521                 }
522         }
523         
524         return (ret_value);
525 }
526
527 int unpackSample(bSample *sample, int how)
528 {
529         char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
530         char * newname;
531         int ret_value = RET_ERROR;
532         PackedFile *pf;
533         
534         if (sample != NULL) {
535                 strcpy(localname, sample->name);
536                 BLI_splitdirstring(localname, fi);
537                 sprintf(localname, "//samples/%s", fi);
538                 
539                 newname = unpackFile(sample->name, localname, sample->packedfile, how);
540                 if (newname != NULL) {
541                         strcpy(sample->name, newname);
542                         MEM_freeN(newname);
543
544                         pf = sample->packedfile;
545                         // because samples and sounds can point to the
546                         // same packedfile we have to check them all
547                         sound_set_packedfile(sample, NULL);
548                         freePackedFile(pf);
549
550                         ret_value = RET_OK;
551                 }
552         }
553         
554         return(ret_value);
555 }
556
557 int unpackImage(Image * ima, int how)
558 {
559         char localname[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX];
560         char * newname;
561         int ret_value = RET_ERROR;
562         
563         if (ima != NULL) {
564                 strcpy(localname, ima->name);
565                 BLI_splitdirstring(localname, fi);
566                 sprintf(localname, "//textures/%s", fi);
567                         
568                 newname = unpackFile(ima->name, localname, ima->packedfile, how);
569                 if (newname != NULL) {
570                         ret_value = RET_OK;
571                         freePackedFile(ima->packedfile);
572                         ima->packedfile = NULL;
573                         strcpy(ima->name, newname);
574                         MEM_freeN(newname);
575                         BKE_image_signal(ima, NULL, IMA_SIGNAL_RELOAD);
576                 }
577         }
578         
579         return(ret_value);
580 }
581
582 void unpackAll(int how)
583 {
584         Image *ima;
585         VFont *vf;
586         bSample *sample;
587                 
588         ima = G.main->image.first;
589         while (ima) {
590                 if (ima->packedfile) {
591                         unpackImage(ima, how);
592                 }
593                 ima= ima->id.next;
594         }
595         
596         vf = G.main->vfont.first;
597         while (vf) {
598                 if (vf->packedfile) {
599                         unpackVFont(vf, how);
600                 }
601                 vf = vf->id.next;
602         }
603
604         sample = samples->first;
605         while (sample) {
606                 if (sample->packedfile) {
607                         unpackSample(sample, how);
608                 }
609                 sample = sample->id.next;
610         }
611 }