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