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