- [#22492] [29159] commit breaks importing of script file that has a reload to self...
[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
33 /* path/file handeling stuff */
34 #ifndef WIN32
35   #include <dirent.h>
36   #include <unistd.h>
37 #else
38   #include <io.h>
39   #include "BLI_winstuff.h"
40 #endif
41
42 #include "MEM_guardedalloc.h"
43
44 #include "DNA_mesh_types.h"
45 #include "DNA_scene_types.h" /* to get the current frame */
46 #include "DNA_sequence_types.h"
47 #include "DNA_vfont_types.h"
48 #include "DNA_windowmanager_types.h"
49
50 #include "BLI_blenlib.h"
51 #include "BLI_bpath.h"
52
53 #include "BKE_global.h"
54 #include "BKE_image.h" /* so we can check the image's type */
55 #include "BKE_main.h" /* so we can access G.main->*.first */
56 #include "BKE_sequencer.h"
57 #include "BKE_utildefines.h"
58 #include "BKE_report.h"
59
60 //XXX #include "BIF_screen.h" /* only for wait cursor */
61 //
62 /* for sequence */
63 //XXX #include "BSE_sequence.h"
64 //XXX define below from BSE_sequence.h - otherwise potentially odd behaviour
65 #define SEQ_HAS_PATH(_seq) ( (_seq)->type==SEQ_MOVIE || (_seq)->type==SEQ_IMAGE || (_seq)->type==SEQ_SOUND )
66
67
68
69 #define FILE_MAX                        240
70
71 /* TODO - BPATH_PLUGIN, BPATH_SEQ */
72 enum BPathTypes {
73         BPATH_IMAGE = 0,
74         BPATH_SOUND,
75         BPATH_FONT,
76         BPATH_LIB,
77         BPATH_SEQ,
78         BPATH_CDATA,
79
80          BPATH_DONE
81 };
82
83 void BLI_bpathIterator_init( struct BPathIterator *bpi, char *base_path ) {
84         bpi->type = BPATH_IMAGE;
85         bpi->data = NULL;
86         
87         bpi->getpath_callback = NULL;
88         bpi->setpath_callback = NULL;
89         
90         /* Sequencer specific */
91         bpi->seqdata.totseq = 0;
92         bpi->seqdata.seq = 0;
93         bpi->seqdata.seqar = NULL;
94         bpi->seqdata.scene = NULL;
95         
96         bpi->base_path= base_path ? base_path : G.sce;
97
98         BLI_bpathIterator_step(bpi);
99 }
100
101 void BLI_bpathIterator_free( struct BPathIterator *bpi ) {
102         if (bpi->seqdata.seqar)
103                 MEM_freeN((void *)bpi->seqdata.seqar);
104         bpi->seqdata.seqar = NULL;
105         bpi->seqdata.scene = NULL;
106 }
107
108 void BLI_bpathIterator_getPath( struct BPathIterator *bpi, char *path) {
109         if (bpi->getpath_callback) {
110                 bpi->getpath_callback( bpi, path );
111         } else {
112                 strcpy(path, bpi->path); /* warning, we assume 'path' are long enough */
113         }
114 }
115
116 void BLI_bpathIterator_setPath( struct BPathIterator *bpi, char *path) {
117         if (bpi->setpath_callback) {
118                 bpi->setpath_callback( bpi, path );
119         } else {
120                 strcpy(bpi->path, path); /* warning, we assume 'path' are long enough */
121         }
122 }
123
124 void BLI_bpathIterator_getPathExpanded( struct BPathIterator *bpi, char *path_expanded) {
125         char *libpath;
126         
127         BLI_bpathIterator_getPath(bpi, path_expanded);
128         libpath = BLI_bpathIterator_getLib(bpi);
129         
130         if (libpath) { /* check the files location relative to its library path */
131                 BLI_path_abs(path_expanded, libpath);
132         } else { /* local data, use the blend files path */
133                 BLI_path_abs(path_expanded, bpi->base_path);
134         }
135         BLI_cleanup_file(NULL, path_expanded);
136 }
137 char* BLI_bpathIterator_getLib( struct BPathIterator *bpi) {
138         return bpi->lib;
139 }
140 char* BLI_bpathIterator_getName( struct BPathIterator *bpi) {
141         return bpi->name;
142 }
143 int     BLI_bpathIterator_getType( struct BPathIterator *bpi) {
144         return bpi->type;
145 }
146 int     BLI_bpathIterator_getPathMaxLen( struct BPathIterator *bpi) {
147         return bpi->len;
148 }
149
150 /* gets the first or the next image that has a path - not a viewer node or generated image */
151 static struct Image *ima_stepdata__internal(struct Image *ima, int step_next) {
152         if (ima==NULL)
153                 return NULL;
154         
155         if (step_next)
156                 ima = ima->id.next;
157         
158         while (ima) {
159                 if (ima->packedfile==NULL && ELEM3(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE))
160                         break;
161                 /* image is not a image with a path, skip it */
162                 ima = ima->id.next;
163         }       
164         return ima;
165 }
166
167 static struct VFont *vf_stepdata__internal(struct VFont *vf, int step_next) {
168         if (vf==NULL)
169                 return NULL;
170         
171         if (step_next)
172                 vf = vf->id.next;
173         
174         while (vf) {
175                 if (vf->packedfile==NULL && BLI_streq(vf->name, "<builtin>")==0) {
176                         break;
177                 }
178                 
179                 /* font with no path, skip it */
180                 vf = vf->id.next;
181         }       
182         return vf;
183 }
184
185 static struct bSound *snd_stepdata__internal(struct bSound *snd, int step_next) {
186         if (snd==NULL)
187                 return NULL;
188         
189         if (step_next)
190                 snd = snd->id.next;
191         
192         while (snd) {
193                 if (snd->packedfile==NULL) {
194                         break;
195                 }
196                 
197                 /* font with no path, skip it */
198                 snd = snd->id.next;
199         }       
200         return snd;
201 }
202
203 static struct Sequence *seq_stepdata__internal(struct BPathIterator *bpi, int step_next)
204 {
205         Editing *ed;
206         Sequence *seq;
207         
208         /* Initializing */
209         if (bpi->seqdata.scene==NULL) {
210                 bpi->seqdata.scene= G.main->scene.first;
211         }
212         
213         if (step_next) {
214                 bpi->seqdata.seq++;
215         }
216         
217         while (bpi->seqdata.scene) {
218                 ed= seq_give_editing(bpi->seqdata.scene, 0);
219                 if (ed) {
220                         if (bpi->seqdata.seqar == NULL) {
221                                 /* allocate the sequencer array */
222                                 seq_array(ed, &bpi->seqdata.seqar, &bpi->seqdata.totseq, 0);
223                                 bpi->seqdata.seq = 0;
224                         }
225                         
226                         if (bpi->seqdata.seq >= bpi->seqdata.totseq) {
227                                 seq = NULL;
228                         } else {
229                                 seq = bpi->seqdata.seqar[bpi->seqdata.seq];
230                                 while (!SEQ_HAS_PATH(seq)) {
231                                         bpi->seqdata.seq++;
232                                         if (bpi->seqdata.seq >= bpi->seqdata.totseq) {
233                                                 seq = NULL;
234                                                 break;
235                                         }
236                                         seq = bpi->seqdata.seqar[bpi->seqdata.seq];
237                                 }
238                         }
239                         if (seq) {
240                                 return seq;
241                         } else {
242                                 /* keep looking through the next scene, reallocate seq array */
243                                 if (bpi->seqdata.seqar) {
244                                         MEM_freeN((void *)bpi->seqdata.seqar);
245                                         bpi->seqdata.seqar = NULL;
246                                 }
247                                 bpi->seqdata.scene = bpi->seqdata.scene->id.next;
248                         }
249                 } else {
250                         /* no seq data in this scene, next */
251                         bpi->seqdata.scene = bpi->seqdata.scene->id.next;
252                 }
253         }
254         
255         return NULL;
256 }
257
258 static void seq_getpath(struct BPathIterator *bpi, char *path) {
259         Sequence *seq = (Sequence *)bpi->data;
260
261         
262         path[0] = '\0'; /* incase we cant get the path */
263         if (seq==NULL) return;
264         if (SEQ_HAS_PATH(seq)) {
265                 if (ELEM3(seq->type, SEQ_IMAGE, SEQ_MOVIE, SEQ_SOUND)) {
266                         BLI_strncpy(path, seq->strip->dir, FILE_MAX);
267                         BLI_add_slash(path); /* incase its missing */
268                         if (seq->strip->stripdata) { /* should always be true! */
269                                 /* Using the first image is weak for image sequences */
270                                 strcat(path, seq->strip->stripdata->name);
271                         } 
272                 } else {
273                         /* simple case */
274                         BLI_strncpy(seq->strip->dir, path, sizeof(seq->strip->dir));
275                 }
276         }
277 }
278
279 static void seq_setpath(struct BPathIterator *bpi, char *path) {
280         Sequence *seq = (Sequence *)bpi->data;
281         if (seq==NULL) return; 
282         
283         if (SEQ_HAS_PATH(seq)) {
284                 if (ELEM3(seq->type, SEQ_IMAGE, SEQ_MOVIE, SEQ_SOUND)) {
285                         BLI_split_dirfile(path, seq->strip->dir, seq->strip->stripdata->name);
286                 } else {
287                         /* simple case */
288                         BLI_strncpy(seq->strip->dir, path, sizeof(seq->strip->dir));
289                 }
290         }
291 }
292
293 static struct Mesh *cdata_stepdata__internal(struct Mesh *me, int step_next) {
294         if (me==NULL)
295                 return NULL;
296         
297         if (step_next)
298                 me = me->id.next;
299         
300         while (me) {
301                 if (me->fdata.external) {
302                         break;
303                 }
304                 
305                 me = me->id.next;
306         }       
307         return me;
308 }
309
310 static void bpi_type_step__internal( struct BPathIterator *bpi) {
311         bpi->type++; /* advance to the next type */
312         bpi->data = NULL;
313         
314         switch (bpi->type) {
315         case BPATH_SEQ:
316                 bpi->getpath_callback = seq_getpath;
317                 bpi->setpath_callback = seq_setpath;
318                 break;
319         default:
320                 bpi->getpath_callback = NULL;
321                 bpi->setpath_callback = NULL;
322                 break;
323         }
324 }
325
326 void BLI_bpathIterator_step( struct BPathIterator *bpi) {
327         while (bpi->type != BPATH_DONE) {
328                 
329                 if  ((bpi->type) == BPATH_IMAGE) {
330                         /*if (bpi->data)        bpi->data = ((ID *)bpi->data)->next;*/
331                         if (bpi->data)  bpi->data = ima_stepdata__internal( (Image *)bpi->data, 1 ); /* must skip images that have no path */
332                         else                    bpi->data = ima_stepdata__internal(G.main->image.first, 0);
333                         
334                         if (bpi->data) {
335                                 /* get the path info from this datatype */
336                                 Image *ima = (Image *)bpi->data;
337                                 
338                                 bpi->lib = ima->id.lib ? ima->id.lib->filepath : NULL;
339                                 bpi->path = ima->name;
340                                 bpi->name = ima->id.name+2;
341                                 bpi->len = sizeof(ima->name);
342                                 
343                                 /* we are done, advancing to the next item, this type worked fine */
344                                 break;
345                                 
346                         } else {
347                                 bpi_type_step__internal(bpi);
348                         }
349                         
350                         
351                 } else if  ((bpi->type) == BPATH_SOUND) {
352                         if (bpi->data)  bpi->data = snd_stepdata__internal( (bSound *)bpi->data, 1 ); /* must skip images that have no path */
353                         else                    bpi->data = snd_stepdata__internal(G.main->sound.first, 0);
354                         
355                         if (bpi->data) {
356                                 /* get the path info from this datatype */
357                                 bSound *snd = (bSound *)bpi->data;
358                                 
359                                 bpi->lib = snd->id.lib ? snd->id.lib->filepath : NULL;
360                                 bpi->path = snd->name;
361                                 bpi->name = snd->id.name+2;
362                                 bpi->len = sizeof(snd->name);
363                                 
364                                 /* we are done, advancing to the next item, this type worked fine */
365                                 break;
366                         } else {
367                                 bpi_type_step__internal(bpi);
368                         }
369                         
370                         
371                 } else if  ((bpi->type) == BPATH_FONT) {
372                         
373                         if (bpi->data)  bpi->data = vf_stepdata__internal( (VFont *)bpi->data, 1 );
374                         else                    bpi->data = vf_stepdata__internal( G.main->vfont.first, 0 );
375                         
376                         if (bpi->data) {
377                                 /* get the path info from this datatype */
378                                 VFont *vf = (VFont *)bpi->data;
379                                 
380                                 bpi->lib = vf->id.lib ? vf->id.lib->filepath : NULL;
381                                 bpi->path = vf->name;
382                                 bpi->name = vf->id.name+2;
383                                 bpi->len = sizeof(vf->name);
384                                 
385                                 /* we are done, advancing to the next item, this type worked fine */
386                                 break;
387                         } else {
388                                 bpi_type_step__internal(bpi);
389                         }
390                         
391                 } else if  ((bpi->type) == BPATH_LIB) {
392                         if (bpi->data)  bpi->data = ((ID *)bpi->data)->next;
393                         else                    bpi->data = G.main->library.first;
394                         
395                         if (bpi->data) {
396                                 /* get the path info from this datatype */
397                                 Library *lib = (Library *)bpi->data;
398                                 
399                                 bpi->lib = NULL;
400                                 bpi->path = lib->name;
401                                 bpi->name = NULL;
402                                 bpi->len = sizeof(lib->name);
403                                 
404                                 /* we are done, advancing to the next item, this type worked fine */
405                                 break;
406                         } else {
407                                 bpi_type_step__internal(bpi);
408                         }
409                 } else if  ((bpi->type) == BPATH_SEQ) {
410                         if (bpi->data)  bpi->data = seq_stepdata__internal( bpi, 1 );
411                         else                    bpi->data = seq_stepdata__internal( bpi, 0 );
412                         if (bpi->data) {
413                                 Sequence *seq = (Sequence *)bpi->data;
414                                 bpi->lib = NULL;
415                                 bpi->name = seq->name+2;
416                                 bpi->len = sizeof(seq->strip->stripdata->name);
417                                 break;
418                         } else {
419                                 bpi_type_step__internal(bpi);
420                         }
421                 } else if  ((bpi->type) == BPATH_CDATA) {
422                         if (bpi->data)  bpi->data = cdata_stepdata__internal( bpi->data, 1 );
423                         else                    bpi->data = cdata_stepdata__internal( G.main->mesh.first, 0 );
424
425                         if (bpi->data) {
426                                 Mesh *me = (Mesh *)bpi->data;
427                                 bpi->lib = me->id.lib ? me->id.lib->filepath : NULL;
428                                 bpi->path = me->fdata.external->filename;
429                                 bpi->name = me->id.name+2;
430                                 bpi->len = sizeof(me->fdata.external->filename);
431                                 break;
432                         } else {
433                                 bpi_type_step__internal(bpi);
434                         }
435                 }
436         }
437 }
438
439 int BLI_bpathIterator_isDone( struct BPathIterator *bpi) {
440         return bpi->type==BPATH_DONE;
441 }
442
443 /* include the path argument */
444 static void bpath_as_report(struct BPathIterator *bpi, const char *message, ReportList *reports)
445 {
446         char *prefix;
447         char *name;
448         char path_expanded[FILE_MAXDIR*2];
449         
450         if(reports==NULL)
451                 return;
452
453         switch(BLI_bpathIterator_getType(bpi)) {
454         case BPATH_IMAGE:
455                 prefix= "Image";
456                 break;
457         case BPATH_SOUND:
458                 prefix= "Sound";
459                 break;
460         case BPATH_FONT:
461                 prefix= "Font";
462                 break;
463         case BPATH_LIB:
464                 prefix= "Library";
465                 break;
466         case BPATH_SEQ:
467                 prefix= "Sequence";
468                 break;
469         case BPATH_CDATA:
470                 prefix= "Mesh Data";
471                 break;
472         default:
473                 prefix= "Unknown";
474                 break;
475         }
476         
477         name = BLI_bpathIterator_getName(bpi);
478         BLI_bpathIterator_getPathExpanded(bpi, path_expanded);
479
480         if(reports) {
481                 if (name)       BKE_reportf(reports, RPT_WARNING, "%s \"%s\", \"%s\": %s", prefix, name, path_expanded, message);
482                 else            BKE_reportf(reports, RPT_WARNING, "%s \"%s\": %s", prefix, path_expanded, message);
483         }
484
485 }
486
487 /* high level function */
488 void checkMissingFiles(char *basepath, ReportList *reports) {
489         struct BPathIterator bpi;
490         
491         /* be sure there is low chance of the path being too short */
492         char filepath_expanded[FILE_MAXDIR*2]; 
493         
494         BLI_bpathIterator_init(&bpi, basepath);
495         while (!BLI_bpathIterator_isDone(&bpi)) {
496                 BLI_bpathIterator_getPathExpanded( &bpi, filepath_expanded );
497                 
498                 if (!BLI_exists(filepath_expanded))
499                         bpath_as_report(&bpi, "file not found", reports);
500
501                 BLI_bpathIterator_step(&bpi);
502         }
503         BLI_bpathIterator_free(&bpi);
504 }
505
506 /* dont log any errors at the moment, should probably do this */
507 void makeFilesRelative(char *basepath, ReportList *reports) {
508         int tot= 0, changed= 0, failed= 0, linked= 0;
509         struct BPathIterator bpi;
510         char filepath[FILE_MAX], *libpath;
511         
512         /* be sure there is low chance of the path being too short */
513         char filepath_relative[(FILE_MAXDIR * 2) + FILE_MAXFILE];
514         
515         BLI_bpathIterator_init(&bpi, basepath);
516         while (!BLI_bpathIterator_isDone(&bpi)) {
517                 BLI_bpathIterator_getPath(&bpi, filepath);
518                 libpath = BLI_bpathIterator_getLib(&bpi);
519                 
520                 if(strncmp(filepath, "//", 2)) {
521                         if (libpath) { /* cant make relative if we are library - TODO, LOG THIS */
522                                 linked++;
523                         } else { /* local data, use the blend files path */
524                                 BLI_strncpy(filepath_relative, filepath, sizeof(filepath_relative));
525                                 /* Important BLI_cleanup_dir runs before the path is made relative
526                                  * because it wont work for paths that start with "//../" */ 
527                                 BLI_cleanup_file(bpi.base_path, filepath_relative); /* fix any /foo/../foo/ */
528                                 BLI_path_rel(filepath_relative, bpi.base_path);
529                                 /* be safe and check the length */
530                                 if (BLI_bpathIterator_getPathMaxLen(&bpi) <= strlen(filepath_relative)) {
531                                         bpath_as_report(&bpi, "couldn't make path relative (too long)", reports);
532                                         failed++;
533                                 } else {
534                                         if(strncmp(filepath_relative, "//", 2)==0) {
535                                                 BLI_bpathIterator_setPath(&bpi, filepath_relative);
536                                                 changed++;
537                                         } else {
538                                                 bpath_as_report(&bpi, "couldn't make path relative", reports);
539                                                 failed++;
540                                         }
541                                 }
542                         }
543                 }
544                 BLI_bpathIterator_step(&bpi);
545                 tot++;
546         }
547         BLI_bpathIterator_free(&bpi);
548
549         if(reports)
550                 BKE_reportf(reports, failed ? RPT_ERROR : RPT_INFO, "Total files %i|Changed %i|Failed %i|Linked %i", tot, changed, failed, linked);
551 }
552
553 /* dont log any errors at the moment, should probably do this -
554  * Verry similar to makeFilesRelative - keep in sync! */
555 void makeFilesAbsolute(char *basepath, ReportList *reports)
556 {
557         int tot= 0, changed= 0, failed= 0, linked= 0;
558
559         struct BPathIterator bpi;
560         char filepath[FILE_MAX], *libpath;
561         
562         /* be sure there is low chance of the path being too short */
563         char filepath_absolute[(FILE_MAXDIR * 2) + FILE_MAXFILE];
564         
565         BLI_bpathIterator_init(&bpi, basepath);
566         while (!BLI_bpathIterator_isDone(&bpi)) {
567                 BLI_bpathIterator_getPath(&bpi, filepath);
568                 libpath = BLI_bpathIterator_getLib(&bpi);
569                 
570                 if(strncmp(filepath, "//", 2)==0) {
571                         if (libpath) { /* cant make absolute if we are library - TODO, LOG THIS */
572                                 linked++;
573                         } else { /* get the expanded path and check it is relative or too long */
574                                 BLI_bpathIterator_getPathExpanded( &bpi, filepath_absolute );
575                                 BLI_cleanup_file(bpi.base_path, filepath_absolute); /* fix any /foo/../foo/ */
576                                 /* to be safe, check the length */
577                                 if (BLI_bpathIterator_getPathMaxLen(&bpi) <= strlen(filepath_absolute)) {
578                                         bpath_as_report(&bpi, "couldn't make absolute (too long)", reports);
579                                         failed++;
580                                 } else {
581                                         if(strncmp(filepath_absolute, "//", 2)) {
582                                                 BLI_bpathIterator_setPath(&bpi, filepath_absolute);
583                                                 changed++;
584                                         } else {
585                                                 bpath_as_report(&bpi, "couldn't make absolute", reports);
586                                                 failed++;
587                                         }
588                                 }
589                         }
590                 }
591                 BLI_bpathIterator_step(&bpi);
592                 tot++;
593         }
594         BLI_bpathIterator_free(&bpi);
595
596         if(reports)
597                 BKE_reportf(reports, failed ? RPT_ERROR : RPT_INFO, "Total files %i|Changed %i|Failed %i|Linked %i", tot, changed, failed, linked);
598 }
599
600
601 /* find this file recursively, use the biggest file so thumbnails dont get used by mistake
602  - dir: subdir to search
603  - filename: set this filename
604  - filesize: filesize for the file
605 */
606 #define MAX_RECUR 16
607 static int findFileRecursive(char *filename_new, const char *dirname, const char *filename, int *filesize, int *recur_depth)
608 {
609         /* file searching stuff */
610         DIR *dir;
611         struct dirent *de;
612         struct stat status;
613         char path[FILE_MAX];
614         int size;
615         
616         dir = opendir(dirname);
617         
618         if (dir==0)
619                 return 0;
620         
621         if (*filesize == -1)
622                 *filesize = 0; /* dir opened fine */
623         
624         while ((de = readdir(dir)) != NULL) {
625                 
626                 if (strcmp(".", de->d_name)==0 || strcmp("..", de->d_name)==0)
627                         continue;
628                 
629                 BLI_join_dirfile(path, dirname, de->d_name);
630                 
631                 if (stat(path, &status) != 0)
632                         continue; /* cant stat, dont bother with this file, could print debug info here */
633                 
634                 if (S_ISREG(status.st_mode)) { /* is file */
635                         if (strncmp(filename, de->d_name, FILE_MAX)==0) { /* name matches */
636                                 /* open the file to read its size */
637                                 size = BLI_filepathsize(path);
638                                 if ((size > 0) && (size > *filesize)) { /* find the biggest file */
639                                         *filesize = size;
640                                         BLI_strncpy(filename_new, path, FILE_MAX);
641                                 }
642                         }
643                 } else if (S_ISDIR(status.st_mode)) { /* is subdir */
644                         if (*recur_depth <= MAX_RECUR) {
645                                 (*recur_depth)++;
646                                 findFileRecursive(filename_new, path, filename, filesize, recur_depth);
647                                 (*recur_depth)--;
648                         }
649                 }
650         }
651         closedir(dir);
652         return 1;
653 }
654
655 /* high level function - call from fileselector */
656 void findMissingFiles(char *basepath, char *str) {
657         struct BPathIterator bpi;
658         
659         /* be sure there is low chance of the path being too short */
660         char filepath_expanded[FILE_MAXDIR*2]; 
661         char filepath[FILE_MAX], *libpath;
662         int filesize, recur_depth;
663         
664         char dirname[FILE_MAX], filename_new[FILE_MAX];
665         
666         //XXX waitcursor( 1 );
667         
668         BLI_split_dirfile(str, dirname, NULL);
669         
670         BLI_bpathIterator_init(&bpi, basepath);
671         
672         while (!BLI_bpathIterator_isDone(&bpi)) {
673                 BLI_bpathIterator_getPath(&bpi, filepath);
674                 libpath = BLI_bpathIterator_getLib(&bpi);
675                 
676                 /* Check if esc was pressed because searching files can be slow */
677                 /*XXX if (blender_test_break()) {
678                         break;
679                 }*/
680                 
681                 if (libpath==NULL) {
682                         
683                         BLI_bpathIterator_getPathExpanded( &bpi, filepath_expanded );
684                         
685                         if (!BLI_exists(filepath_expanded)) {
686                                 /* can the dir be opened? */
687                                 filesize = -1;
688                                 recur_depth = 0;
689                                 
690                                 findFileRecursive(filename_new, dirname, BLI_path_basename(filepath), &filesize, &recur_depth);
691                                 if (filesize == -1) { /* could not open dir */
692                                         printf("Could not open dir \"%s\"\n", dirname);
693                                         return;
694                                 }
695                                 
696                                 if (filesize > 0) {
697                                         
698                                         if (BLI_bpathIterator_getPathMaxLen( &bpi ) < strlen(filename_new)) { 
699                                                 printf("cannot set path \"%s\" too long!", filename_new);
700                                         } else {
701                                                 /* copy the found path into the old one */
702                                                 if (G.relbase_valid)
703                                                         BLI_path_rel(filename_new, bpi.base_path);
704                                                 
705                                                 BLI_bpathIterator_setPath( &bpi, filename_new );
706                                         }
707                                 }
708                         }
709                 }
710                 BLI_bpathIterator_step(&bpi);
711         }
712         BLI_bpathIterator_free(&bpi);
713         
714         //XXX waitcursor( 0 );
715 }