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