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