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