merge with/from trunk at r35190
[blender.git] / source / blender / blenlib / intern / bpath.c
1 /*
2  *
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): Campbell barton
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <sys/stat.h>
30
31 #include <string.h>
32 #include <assert.h>
33
34 /* path/file handeling stuff */
35 #ifndef WIN32
36   #include <dirent.h>
37   #include <unistd.h>
38 #else
39   #include <io.h>
40   #include "BLI_winstuff.h"
41 #endif
42
43 #include "MEM_guardedalloc.h"
44
45 #include "DNA_mesh_types.h"
46 #include "DNA_scene_types.h" /* to get the current frame */
47 #include "DNA_image_types.h"
48 #include "DNA_texture_types.h"
49 #include "DNA_text_types.h"
50 #include "DNA_sound_types.h"
51 #include "DNA_sequence_types.h"
52 #include "DNA_vfont_types.h"
53 #include "DNA_windowmanager_types.h"
54
55 #include "BLI_blenlib.h"
56 #include "BLI_bpath.h"
57 #include "BLI_utildefines.h"
58
59 #include "BKE_global.h"
60 #include "BKE_image.h" /* so we can check the image's type */
61 #include "BKE_sequencer.h"
62 #include "BKE_main.h"
63 #include "BKE_utildefines.h"
64 #include "BKE_report.h"
65
66 //XXX #include "BIF_screen.h" /* only for wait cursor */
67 //
68 /* for sequence */
69 //XXX #include "BSE_sequence.h"
70 //XXX define below from BSE_sequence.h - otherwise potentially odd behaviour
71
72
73 typedef struct BPathIteratorSeqData {
74         int totseq;
75         int seq;
76         struct Sequence **seqar; /* Sequence */
77         struct Scene *scene;                    /* Current scene */
78 } BPathIteratorSeqData;
79
80 typedef struct BPathIterator {
81         char*   _path; /* never access directly, use BLI_bpathIterator_getPath */
82         const char*     _lib;
83         const char*     _name;
84         void*   data;
85         int             len;
86         int             type;
87         int             flag; /* iterator options */
88
89         void (*setpath_callback)(struct BPathIterator *, const char *);
90         void (*getpath_callback)(struct BPathIterator *, char *);
91
92         const char*     base_path; /* base path, the directry the blend file is in - normally bmain->name */
93
94         Main *bmain;
95
96         /* only for seq data */
97         struct BPathIteratorSeqData seqdata;
98 } BPathIterator;
99
100 #define FILE_MAX                        240
101
102
103 /* TODO - BPATH_PLUGIN, BPATH_SEQ */
104 enum BPathTypes {
105         BPATH_IMAGE= 0,
106         BPATH_TEXTURE,
107         BPATH_TEXT,
108         BPATH_SOUND,
109         BPATH_FONT,
110         BPATH_LIB,
111         BPATH_SEQ,
112         BPATH_CDATA,
113
114          BPATH_DONE
115 };
116
117 void BLI_bpathIterator_init(struct BPathIterator **bpi_pt, Main *bmain, const char *basedir, const int flag)
118 {
119         BPathIterator *bpi;
120
121         bpi= MEM_mallocN(sizeof(BPathIterator), "BLI_bpathIterator_init");
122         *bpi_pt= bpi;
123
124         bpi->type= BPATH_IMAGE;
125         bpi->data= NULL;
126         
127         bpi->getpath_callback= NULL;
128         bpi->setpath_callback= NULL;
129         
130         /* Sequencer specific */
131         bpi->seqdata.totseq= 0;
132         bpi->seqdata.seq= 0;
133         bpi->seqdata.seqar= NULL;
134         bpi->seqdata.scene= NULL;
135
136         bpi->flag= flag;
137
138         bpi->base_path= basedir; /* normally bmain->name */
139         bpi->bmain= bmain;
140
141         BLI_bpathIterator_step(bpi);
142 }
143
144 #if 0
145 static void BLI_bpathIterator_alloc(struct BPathIterator **bpi) {
146         *bpi= MEM_mallocN(sizeof(BPathIterator), "BLI_bpathIterator_alloc");
147 }
148 #endif
149
150 void BLI_bpathIterator_free(struct BPathIterator *bpi) {
151         if (bpi->seqdata.seqar)
152                 MEM_freeN((void *)bpi->seqdata.seqar);
153         bpi->seqdata.seqar= NULL;
154         bpi->seqdata.scene= NULL;
155         
156         MEM_freeN(bpi);
157 }
158
159 void BLI_bpathIterator_getPath(struct BPathIterator *bpi, char *path) {
160         if (bpi->getpath_callback) {
161                 bpi->getpath_callback(bpi, path);
162         } else {
163                 strcpy(path, bpi->_path); /* warning, we assume 'path' are long enough */
164         }
165 }
166
167 void BLI_bpathIterator_setPath(struct BPathIterator *bpi, const char *path) {
168         if (bpi->setpath_callback) {
169                 bpi->setpath_callback(bpi, path);
170         } else {
171                 strcpy(bpi->_path, path); /* warning, we assume 'path' are long enough */
172         }
173 }
174
175 void BLI_bpathIterator_getPathExpanded(struct BPathIterator *bpi, char *path_expanded) {
176         const char *libpath;
177         
178         BLI_bpathIterator_getPath(bpi, path_expanded);
179         libpath= BLI_bpathIterator_getLib(bpi);
180         
181         if (libpath) { /* check the files location relative to its library path */
182                 BLI_path_abs(path_expanded, libpath);
183         } else { /* local data, use the blend files path */
184                 BLI_path_abs(path_expanded, bpi->base_path);
185         }
186         BLI_cleanup_file(NULL, path_expanded);
187 }
188 const char* BLI_bpathIterator_getLib(struct BPathIterator *bpi) {
189         return bpi->_lib;
190 }
191 const char* BLI_bpathIterator_getName(struct BPathIterator *bpi) {
192         return bpi->_name;
193 }
194 int     BLI_bpathIterator_getType(struct BPathIterator *bpi) {
195         return bpi->type;
196 }
197 int     BLI_bpathIterator_getPathMaxLen(struct BPathIterator *bpi) {
198         return bpi->len;
199 }
200 const char* BLI_bpathIterator_getBasePath(struct BPathIterator *bpi) {
201         return bpi->base_path;
202 }
203
204 /* gets the first or the next image that has a path - not a viewer node or generated image */
205 static struct Image *ima_stepdata__internal(struct Image *ima, const int step_next, const int flag)
206 {
207         if (ima==NULL)
208                 return NULL;
209         
210         if (step_next)
211                 ima= ima->id.next;
212         
213         while (ima) {
214                 if (ELEM3(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
215                         if(ima->packedfile==NULL || (flag & BPATH_USE_PACKED)) {
216                                 break;
217                         }
218                 }
219                 /* image is not a image with a path, skip it */
220                 ima= ima->id.next;
221         }       
222         return ima;
223 }
224
225 static struct Tex *tex_stepdata__internal(struct Tex *tex, const int step_next, const int UNUSED(flag))
226 {
227         if (tex==NULL)
228                 return NULL;
229
230         if (step_next)
231                 tex= tex->id.next;
232
233         while (tex) {
234                 if (tex->type == TEX_VOXELDATA && TEX_VD_IS_SOURCE_PATH(tex->vd->file_format))
235                         break;
236                 /* image is not a image with a path, skip it */
237                 tex= tex->id.next;
238         }       
239         return tex;
240 }
241
242 static struct Text *text_stepdata__internal(struct Text *text, const int step_next, const int UNUSED(flag))
243 {
244         if (text==NULL)
245                 return NULL;
246
247         if (step_next)
248                 text= text->id.next;
249
250         while (text) {
251                 if (text->name)
252                         break;
253                 /* image is not a image with a path, skip it */
254                 text= text->id.next;
255         }       
256         return text;
257 }
258
259 static struct VFont *vf_stepdata__internal(struct VFont *vf, const int step_next, const int flag)
260 {
261         if (vf==NULL)
262                 return NULL;
263         
264         if (step_next)
265                 vf= vf->id.next;
266         
267         while (vf) {
268                 if (strcmp(vf->name, FO_BUILTIN_NAME)!=0) {
269                         if(vf->packedfile==NULL || (flag & BPATH_USE_PACKED)) {
270                                 break;
271                         }
272                 }
273                 
274                 /* font with no path, skip it */
275                 vf= vf->id.next;
276         }       
277         return vf;
278 }
279
280 static struct bSound *snd_stepdata__internal(struct bSound *snd, int step_next, const int flag)
281 {
282         if (snd==NULL)
283                 return NULL;
284         
285         if (step_next)
286                 snd= snd->id.next;
287         
288         while (snd) {
289                 if(snd->packedfile==NULL || (flag & BPATH_USE_PACKED)) {
290                         break;
291                 }
292
293                 /* font with no path, skip it */
294                 snd= snd->id.next;
295         }       
296         return snd;
297 }
298
299 static struct Sequence *seq_stepdata__internal(struct BPathIterator *bpi, int step_next)
300 {
301         Editing *ed;
302         Sequence *seq;
303         
304         /* Initializing */
305         if (bpi->seqdata.scene==NULL) {
306                 bpi->seqdata.scene= bpi->bmain->scene.first;
307         }
308         
309         if (step_next) {
310                 bpi->seqdata.seq++;
311         }
312         
313         while (bpi->seqdata.scene) {
314                 ed= seq_give_editing(bpi->seqdata.scene, 0);
315                 if (ed) {
316                         if (bpi->seqdata.seqar == NULL) {
317                                 /* allocate the sequencer array */
318                                 seq_array(ed, &bpi->seqdata.seqar, &bpi->seqdata.totseq, 0);
319                                 bpi->seqdata.seq= 0;
320                         }
321                         
322                         if (bpi->seqdata.seq >= bpi->seqdata.totseq) {
323                                 seq= NULL;
324                         } else {
325                                 seq= bpi->seqdata.seqar[bpi->seqdata.seq];
326                                 while (!SEQ_HAS_PATH(seq) && seq->plugin==NULL) {
327                                         bpi->seqdata.seq++;
328                                         if (bpi->seqdata.seq >= bpi->seqdata.totseq) {
329                                                 seq= NULL;
330                                                 break;
331                                         }
332                                         seq= bpi->seqdata.seqar[bpi->seqdata.seq];
333                                 }
334                         }
335                         if (seq) {
336                                 return seq;
337                         } else {
338                                 /* keep looking through the next scene, reallocate seq array */
339                                 if (bpi->seqdata.seqar) {
340                                         MEM_freeN((void *)bpi->seqdata.seqar);
341                                         bpi->seqdata.seqar= NULL;
342                                 }
343                                 bpi->seqdata.scene= bpi->seqdata.scene->id.next;
344                         }
345                 } else {
346                         /* no seq data in this scene, next */
347                         bpi->seqdata.scene= bpi->seqdata.scene->id.next;
348                 }
349         }
350         
351         return NULL;
352 }
353
354 static void seq_getpath(struct BPathIterator *bpi, char *path) {
355         Sequence *seq= (Sequence *)bpi->data;
356
357         
358         path[0]= '\0'; /* incase we cant get the path */
359         if (seq==NULL) return;
360         if (SEQ_HAS_PATH(seq)) {
361                 if (ELEM3(seq->type, SEQ_IMAGE, SEQ_MOVIE, SEQ_SOUND)) {
362                         BLI_strncpy(path, seq->strip->dir, FILE_MAX);
363                         BLI_add_slash(path); /* incase its missing */
364                         if (seq->strip->stripdata) { /* should always be true! */
365                                 /* Using the first image is weak for image sequences */
366                                 strcat(path, seq->strip->stripdata->name);
367                         } 
368                 }
369                 else {
370                         /* simple case */
371                         BLI_strncpy(seq->strip->dir, path, sizeof(seq->strip->dir));
372                 }
373         }
374         else if (seq->plugin) {
375                 BLI_strncpy(seq->plugin->name, path, sizeof(seq->plugin->name));
376         }
377 }
378
379 static void seq_setpath(struct BPathIterator *bpi, const char *path) {
380         Sequence *seq= (Sequence *)bpi->data;
381         if (seq==NULL) return; 
382         
383         if (SEQ_HAS_PATH(seq)) {
384                 if (ELEM3(seq->type, SEQ_IMAGE, SEQ_MOVIE, SEQ_SOUND)) {
385                         BLI_split_dirfile(path, seq->strip->dir, seq->strip->stripdata->name);
386                 }
387                 else {
388                         /* simple case */
389                         BLI_strncpy(seq->strip->dir, path, sizeof(seq->strip->dir));
390                 }
391         }
392         else if (seq->plugin) {
393                 BLI_strncpy(seq->plugin->name, path, sizeof(seq->plugin->name));
394         }
395 }
396
397 static void text_getpath(struct BPathIterator *bpi, char *path) {
398         Text *text= (Text *)bpi->data;
399         path[0]= '\0'; /* incase we cant get the path */
400         if(text->name) {
401                 strcpy(path, text->name);
402         }
403 }
404
405 static void text_setpath(struct BPathIterator *bpi, const char *path) {
406         Text *text= (Text *)bpi->data;
407         if (text==NULL) return; 
408
409         if(text->name) {
410                 MEM_freeN(text->name);
411         }
412
413         text->name= BLI_strdup(path);
414 }
415
416 static struct Mesh *cdata_stepdata__internal(struct Mesh *me, int step_next) {
417         if (me==NULL)
418                 return NULL;
419         
420         if (step_next)
421                 me= me->id.next;
422         
423         while (me) {
424                 if (me->fdata.external) {
425                         break;
426                 }
427                 
428                 me= me->id.next;
429         }       
430         return me;
431 }
432
433 static void bpi_type_step__internal(struct BPathIterator *bpi) {
434         bpi->type++; /* advance to the next type */
435         bpi->data= NULL;
436         
437         switch (bpi->type) {
438         case BPATH_SEQ:
439                 bpi->getpath_callback= seq_getpath;
440                 bpi->setpath_callback= seq_setpath;
441                 break;
442         case BPATH_TEXT: /* path is malloc'd */
443                 bpi->getpath_callback= text_getpath;
444                 bpi->setpath_callback= text_setpath;
445                 break;
446         default:
447                 bpi->getpath_callback= NULL;
448                 bpi->setpath_callback= NULL;
449                 break;
450         }
451 }
452
453 void BLI_bpathIterator_step(struct BPathIterator *bpi) {
454         while (bpi->type != BPATH_DONE) {
455                 
456                 if  ((bpi->type) == BPATH_IMAGE) {
457                         /*if (bpi->data)        bpi->data= ((ID *)bpi->data)->next;*/
458                         if (bpi->data)  bpi->data= ima_stepdata__internal((Image *)bpi->data, 1, bpi->flag); /* must skip images that have no path */
459                         else                    bpi->data= ima_stepdata__internal(bpi->bmain->image.first, 0, bpi->flag);
460                         
461                         if (bpi->data) {
462                                 /* get the path info from this datatype */
463                                 Image *ima= (Image *)bpi->data;
464                                 
465                                 bpi->_lib= ima->id.lib ? ima->id.lib->filepath : NULL;
466                                 bpi->_path= ima->name;
467                                 bpi->_name= ima->id.name+2;
468                                 bpi->len= sizeof(ima->name);
469                                 
470                                 /* we are done, advancing to the next item, this type worked fine */
471                                 break;
472
473                         } else {
474                                 bpi_type_step__internal(bpi);
475                         }
476                 }
477
478                 if  ((bpi->type) == BPATH_TEXTURE) {
479                         /*if (bpi->data)        bpi->data= ((ID *)bpi->data)->next;*/
480                         if (bpi->data)  bpi->data= tex_stepdata__internal( (Tex *)bpi->data, 1, bpi->flag); /* must skip images that have no path */
481                         else                    bpi->data= tex_stepdata__internal(bpi->bmain->tex.first, 0, bpi->flag);
482
483                         if (bpi->data) {
484                                 /* get the path info from this datatype */
485                                 Tex *tex= (Tex *)bpi->data;
486
487                                 if(tex->type == TEX_VOXELDATA) {
488                                         bpi->_lib= tex->id.lib ? tex->id.lib->filepath : NULL;
489                                         bpi->_path= tex->vd->source_path;
490                                         bpi->_name= tex->id.name+2;
491                                         bpi->len= sizeof(tex->vd->source_path);
492                                 }
493                                 else {
494                                         assert(!"Texture has no path, incorrect step 'tex_stepdata__internal'");
495                                 }
496
497                                 /* we are done, advancing to the next item, this type worked fine */
498                                 break;
499
500                         } else {
501                                 bpi_type_step__internal(bpi);
502                         }
503                 }
504
505                 if  ((bpi->type) == BPATH_TEXT) {
506                         /*if (bpi->data)        bpi->data= ((ID *)bpi->data)->next;*/
507                         if (bpi->data)  bpi->data= text_stepdata__internal((Text *)bpi->data, 1, bpi->flag); /* must skip images that have no path */
508                         else                    bpi->data= text_stepdata__internal(bpi->bmain->text.first, 0, bpi->flag);
509
510                         if (bpi->data) {
511                                 /* get the path info from this datatype */
512                                 Text *text= (Text *)bpi->data;
513
514                                 bpi->_lib= text->id.lib ? text->id.lib->filepath : NULL;
515                                 bpi->_path= NULL; /* bpi->path= text->name; */ /* get/set functions override. */
516                                 bpi->_name= text->id.name+2;
517                                 bpi->len= FILE_MAX; /* malloc'd but limit anyway since large paths may mess up other areas */
518
519                                 /* we are done, advancing to the next item, this type worked fine */
520                                 break;
521
522                         } else {
523                                 bpi_type_step__internal(bpi);
524                         }
525                 }
526
527                 else if  ((bpi->type) == BPATH_SOUND) {
528                         if (bpi->data)  bpi->data= snd_stepdata__internal((bSound *)bpi->data, 1, bpi->flag); /* must skip images that have no path */
529                         else                    bpi->data= snd_stepdata__internal(bpi->bmain->sound.first, 0, bpi->flag);
530
531                         if (bpi->data) {
532                                 /* get the path info from this datatype */
533                                 bSound *snd= (bSound *)bpi->data;
534
535                                 bpi->_lib= snd->id.lib ? snd->id.lib->filepath : NULL;
536                                 bpi->_path= snd->name;
537                                 bpi->_name= snd->id.name+2;
538                                 bpi->len= sizeof(snd->name);
539
540                                 /* we are done, advancing to the next item, this type worked fine */
541                                 break;
542                         } else {
543                                 bpi_type_step__internal(bpi);
544                         }
545                         
546                         
547                 } else if  ((bpi->type) == BPATH_FONT) {
548                         
549                         if (bpi->data)  bpi->data= vf_stepdata__internal((VFont *)bpi->data, 1, bpi->flag);
550                         else                    bpi->data= vf_stepdata__internal(bpi->bmain->vfont.first, 0, bpi->flag);
551                         
552                         if (bpi->data) {
553                                 /* get the path info from this datatype */
554                                 VFont *vf= (VFont *)bpi->data;
555
556                                 bpi->_lib= vf->id.lib ? vf->id.lib->filepath : NULL;
557                                 bpi->_path= vf->name;
558                                 bpi->_name= vf->id.name+2;
559                                 bpi->len= sizeof(vf->name);
560
561                                 /* we are done, advancing to the next item, this type worked fine */
562                                 break;
563                         } else {
564                                 bpi_type_step__internal(bpi);
565                         }
566
567                 } else if  ((bpi->type) == BPATH_LIB) {
568                         if (bpi->data)  bpi->data= ((ID *)bpi->data)->next;
569                         else                    bpi->data= bpi->bmain->library.first;
570                         
571                         if (bpi->data) {
572                                 /* get the path info from this datatype */
573                                 Library *lib= (Library *)bpi->data;
574                                 
575                                 bpi->_lib= NULL;
576                                 bpi->_path= lib->name;
577                                 bpi->_name= NULL;
578                                 bpi->len= sizeof(lib->name);
579                                 
580                                 /* we are done, advancing to the next item, this type worked fine */
581                                 break;
582                         } else {
583                                 bpi_type_step__internal(bpi);
584                         }
585                 } else if  ((bpi->type) == BPATH_SEQ) {
586                         if (bpi->data)  bpi->data= seq_stepdata__internal( bpi, 1 );
587                         else                    bpi->data= seq_stepdata__internal( bpi, 0 );
588                         if (bpi->data) {
589                                 Sequence *seq= (Sequence *)bpi->data;
590                                 bpi->_lib= NULL;
591                                 bpi->_name= seq->name+2;
592                                 bpi->len= seq->plugin ? sizeof(seq->plugin->name) : sizeof(seq->strip->dir) + sizeof(seq->strip->stripdata->name);
593                                 break;
594                         } else {
595                                 bpi_type_step__internal(bpi);
596                         }
597                 } else if  ((bpi->type) == BPATH_CDATA) {
598                         if (bpi->data)  bpi->data= cdata_stepdata__internal( bpi->data, 1 );
599                         else                    bpi->data= cdata_stepdata__internal( bpi->bmain->mesh.first, 0 );
600
601                         if (bpi->data) {
602                                 Mesh *me= (Mesh *)bpi->data;
603                                 bpi->_lib= me->id.lib ? me->id.lib->filepath : NULL;
604                                 bpi->_path= me->fdata.external->filename;
605                                 bpi->_name= me->id.name+2;
606                                 bpi->len= sizeof(me->fdata.external->filename);
607                                 break;
608                         } else {
609                                 bpi_type_step__internal(bpi);
610                         }
611                 }
612         }
613 }
614
615 int BLI_bpathIterator_isDone( struct BPathIterator *bpi) {
616         return bpi->type==BPATH_DONE;
617 }
618
619 /* include the path argument */
620 static void bpath_as_report(struct BPathIterator *bpi, const char *message, ReportList *reports)
621 {
622         const char *prefix;
623         const char *name;
624         char path_expanded[FILE_MAXDIR*2];
625         
626         if(reports==NULL)
627                 return;
628
629         switch(BLI_bpathIterator_getType(bpi)) {
630         case BPATH_IMAGE:
631                 prefix= "Image";
632                 break;
633         case BPATH_TEXTURE:
634                 prefix= "Texture";
635                 break;
636         case BPATH_TEXT:
637                 prefix= "Text";
638                 break;
639         case BPATH_SOUND:
640                 prefix= "Sound";
641                 break;
642         case BPATH_FONT:
643                 prefix= "Font";
644                 break;
645         case BPATH_LIB:
646                 prefix= "Library";
647                 break;
648         case BPATH_SEQ:
649                 prefix= "Sequence";
650                 break;
651         case BPATH_CDATA:
652                 prefix= "Mesh Data";
653                 break;
654         default:
655                 prefix= "Unknown";
656                 break;
657         }
658         
659         name= BLI_bpathIterator_getName(bpi);
660         BLI_bpathIterator_getPathExpanded(bpi, path_expanded);
661
662         if(reports) {
663                 if (name)       BKE_reportf(reports, RPT_WARNING, "%s \"%s\", \"%s\": %s", prefix, name, path_expanded, message);
664                 else            BKE_reportf(reports, RPT_WARNING, "%s \"%s\": %s", prefix, path_expanded, message);
665         }
666
667 }
668
669 /* high level function */
670 void checkMissingFiles(Main *bmain, ReportList *reports) {
671         struct BPathIterator *bpi;
672         
673         /* be sure there is low chance of the path being too short */
674         char filepath_expanded[FILE_MAXDIR*2]; 
675         
676         BLI_bpathIterator_init(&bpi, bmain, bmain->name, 0);
677         while (!BLI_bpathIterator_isDone(bpi)) {
678                 BLI_bpathIterator_getPathExpanded(bpi, filepath_expanded);
679                 
680                 if (!BLI_exists(filepath_expanded))
681                         bpath_as_report(bpi, "file not found", reports);
682
683                 BLI_bpathIterator_step(bpi);
684         }
685         BLI_bpathIterator_free(bpi);
686 }
687
688 /* dont log any errors at the moment, should probably do this */
689 void makeFilesRelative(Main *bmain, const char *basedir, ReportList *reports) {
690         int tot= 0, changed= 0, failed= 0, linked= 0;
691         struct BPathIterator *bpi;
692         char filepath[FILE_MAX];
693         const char *libpath;
694         
695         /* be sure there is low chance of the path being too short */
696         char filepath_relative[(FILE_MAXDIR * 2) + FILE_MAXFILE];
697         
698         BLI_bpathIterator_init(&bpi, bmain, basedir, 0);
699         while (!BLI_bpathIterator_isDone(bpi)) {
700                 BLI_bpathIterator_getPath(bpi, filepath);
701                 libpath= BLI_bpathIterator_getLib(bpi);
702                 
703                 if(strncmp(filepath, "//", 2)) {
704                         if (libpath) { /* cant make relative if we are library - TODO, LOG THIS */
705                                 linked++;
706                         } else { /* local data, use the blend files path */
707                                 BLI_strncpy(filepath_relative, filepath, sizeof(filepath_relative));
708                                 /* Important BLI_cleanup_dir runs before the path is made relative
709                                  * because it wont work for paths that start with "//../" */ 
710                                 BLI_cleanup_file(bpi->base_path, filepath_relative); /* fix any /foo/../foo/ */
711                                 BLI_path_rel(filepath_relative, bpi->base_path);
712                                 /* be safe and check the length */
713                                 if (BLI_bpathIterator_getPathMaxLen(bpi) <= strlen(filepath_relative)) {
714                                         bpath_as_report(bpi, "couldn't make path relative (too long)", reports);
715                                         failed++;
716                                 } else {
717                                         if(strncmp(filepath_relative, "//", 2)==0) {
718                                                 BLI_bpathIterator_setPath(bpi, filepath_relative);
719                                                 changed++;
720                                         } else {
721                                                 bpath_as_report(bpi, "couldn't make path relative", reports);
722                                                 failed++;
723                                         }
724                                 }
725                         }
726                 }
727                 BLI_bpathIterator_step(bpi);
728                 tot++;
729         }
730         BLI_bpathIterator_free(bpi);
731
732         if(reports)
733                 BKE_reportf(reports, failed ? RPT_ERROR : RPT_INFO, "Total files %i|Changed %i|Failed %i|Linked %i", tot, changed, failed, linked);
734 }
735
736 /* dont log any errors at the moment, should probably do this -
737  * Verry similar to makeFilesRelative - keep in sync! */
738 void makeFilesAbsolute(Main *bmain, const char *basedir, ReportList *reports)
739 {
740         int tot= 0, changed= 0, failed= 0, linked= 0;
741
742         struct BPathIterator *bpi;
743         char filepath[FILE_MAX];
744         const char *libpath;
745         
746         /* be sure there is low chance of the path being too short */
747         char filepath_absolute[(FILE_MAXDIR * 2) + FILE_MAXFILE];
748         
749         BLI_bpathIterator_init(&bpi, bmain, basedir, 0);
750         while (!BLI_bpathIterator_isDone(bpi)) {
751                 BLI_bpathIterator_getPath(bpi, filepath);
752                 libpath= BLI_bpathIterator_getLib(bpi);
753                 
754                 if(strncmp(filepath, "//", 2)==0) {
755                         if (libpath) { /* cant make absolute if we are library - TODO, LOG THIS */
756                                 linked++;
757                         } else { /* get the expanded path and check it is relative or too long */
758                                 BLI_bpathIterator_getPathExpanded(bpi, filepath_absolute);
759                                 BLI_cleanup_file(bpi->base_path, filepath_absolute); /* fix any /foo/../foo/ */
760                                 /* to be safe, check the length */
761                                 if (BLI_bpathIterator_getPathMaxLen(bpi) <= strlen(filepath_absolute)) {
762                                         bpath_as_report(bpi, "couldn't make absolute (too long)", reports);
763                                         failed++;
764                                 } else {
765                                         if(strncmp(filepath_absolute, "//", 2)) {
766                                                 BLI_bpathIterator_setPath(bpi, filepath_absolute);
767                                                 changed++;
768                                         } else {
769                                                 bpath_as_report(bpi, "couldn't make absolute", reports);
770                                                 failed++;
771                                         }
772                                 }
773                         }
774                 }
775                 BLI_bpathIterator_step(bpi);
776                 tot++;
777         }
778         BLI_bpathIterator_free(bpi);
779
780         if(reports)
781                 BKE_reportf(reports, failed ? RPT_ERROR : RPT_INFO, "Total files %i|Changed %i|Failed %i|Linked %i", tot, changed, failed, linked);
782 }
783
784
785 /* find this file recursively, use the biggest file so thumbnails dont get used by mistake
786  - dir: subdir to search
787  - filename: set this filename
788  - filesize: filesize for the file
789 */
790 #define MAX_RECUR 16
791 static int findFileRecursive(char *filename_new, const char *dirname, const char *filename, int *filesize, int *recur_depth)
792 {
793         /* file searching stuff */
794         DIR *dir;
795         struct dirent *de;
796         struct stat status;
797         char path[FILE_MAX];
798         int size;
799         
800         dir= opendir(dirname);
801         
802         if (dir==NULL)
803                 return 0;
804         
805         if (*filesize == -1)
806                 *filesize= 0; /* dir opened fine */
807         
808         while ((de= readdir(dir)) != NULL) {
809                 
810                 if (strcmp(".", de->d_name)==0 || strcmp("..", de->d_name)==0)
811                         continue;
812                 
813                 BLI_join_dirfile(path, sizeof(path), dirname, de->d_name);
814                 
815                 if (stat(path, &status) != 0)
816                         continue; /* cant stat, dont bother with this file, could print debug info here */
817                 
818                 if (S_ISREG(status.st_mode)) { /* is file */
819                         if (strncmp(filename, de->d_name, FILE_MAX)==0) { /* name matches */
820                                 /* open the file to read its size */
821                                 size= status.st_size;
822                                 if ((size > 0) && (size > *filesize)) { /* find the biggest file */
823                                         *filesize= size;
824                                         BLI_strncpy(filename_new, path, FILE_MAX);
825                                 }
826                         }
827                 } else if (S_ISDIR(status.st_mode)) { /* is subdir */
828                         if (*recur_depth <= MAX_RECUR) {
829                                 (*recur_depth)++;
830                                 findFileRecursive(filename_new, path, filename, filesize, recur_depth);
831                                 (*recur_depth)--;
832                         }
833                 }
834         }
835         closedir(dir);
836         return 1;
837 }
838
839 /* high level function - call from fileselector */
840 void findMissingFiles(Main *bmain, const char *str) {
841         struct BPathIterator *bpi;
842         
843         /* be sure there is low chance of the path being too short */
844         char filepath_expanded[FILE_MAXDIR*2]; 
845         char filepath[FILE_MAX];
846         const char *libpath;
847         int filesize, recur_depth;
848         
849         char dirname[FILE_MAX], filename_new[FILE_MAX];
850         
851         //XXX waitcursor( 1 );
852         
853         BLI_split_dirfile(str, dirname, NULL);
854         
855         BLI_bpathIterator_init(&bpi, bmain, bmain->name, 0);
856         
857         while (!BLI_bpathIterator_isDone(bpi)) {
858                 BLI_bpathIterator_getPath(bpi, filepath);
859                 libpath= BLI_bpathIterator_getLib(bpi);
860                 
861                 /* Check if esc was pressed because searching files can be slow */
862                 /*XXX if (blender_test_break()) {
863                         break;
864                 }*/
865                 
866                 if (libpath==NULL) {
867                         
868                         BLI_bpathIterator_getPathExpanded(bpi, filepath_expanded);
869                         
870                         if (!BLI_exists(filepath_expanded)) {
871                                 /* can the dir be opened? */
872                                 filesize= -1;
873                                 recur_depth= 0;
874                                 
875                                 findFileRecursive(filename_new, dirname, BLI_path_basename(filepath), &filesize, &recur_depth);
876                                 if (filesize == -1) { /* could not open dir */
877                                         printf("Could not open dir \"%s\"\n", dirname);
878                                         return;
879                                 }
880                                 
881                                 if (filesize > 0) {
882                                         
883                                         if (BLI_bpathIterator_getPathMaxLen(bpi) < strlen(filename_new)) { 
884                                                 printf("cannot set path \"%s\" too long!", filename_new);
885                                         } else {
886                                                 /* copy the found path into the old one */
887                                                 if (G.relbase_valid)
888                                                         BLI_path_rel(filename_new, bpi->base_path);
889                                                 
890                                                 BLI_bpathIterator_setPath(bpi, filename_new);
891                                         }
892                                 }
893                         }
894                 }
895                 BLI_bpathIterator_step(bpi);
896         }
897         BLI_bpathIterator_free(bpi);
898         
899         //XXX waitcursor( 0 );
900 }