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