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