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