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