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