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