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