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