3 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
19 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20 * All rights reserved.
22 * The Original Code is: all of this file.
24 * Contributor(s): Campbell barton
26 * ***** END GPL LICENSE BLOCK *****
29 /** \file blender/blenlib/intern/bpath.c
39 /* path/file handeling stuff */
45 #include "BLI_winstuff.h"
48 #include "MEM_guardedalloc.h"
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"
60 #include "BLI_blenlib.h"
61 #include "BLI_bpath.h"
62 #include "BLI_utildefines.h"
64 #include "BKE_global.h"
65 #include "BKE_image.h" /* so we can check the image's type */
66 #include "BKE_sequencer.h"
68 #include "BKE_utildefines.h"
69 #include "BKE_report.h"
71 //XXX #include "BIF_screen.h" /* only for wait cursor */
74 //XXX #include "BSE_sequence.h"
75 //XXX define below from BSE_sequence.h - otherwise potentially odd behaviour
78 typedef struct BPathIteratorSeqData {
81 struct Sequence **seqar; /* Sequence */
82 struct Scene *scene; /* Current scene */
83 } BPathIteratorSeqData;
85 typedef struct BPathIterator {
86 char* _path; /* never access directly, use BLI_bpathIterator_getPath */
92 int flag; /* iterator options */
94 void (*setpath_callback)(struct BPathIterator *, const char *);
95 void (*getpath_callback)(struct BPathIterator *, char *);
97 const char* base_path; /* base path, the directry the blend file is in - normally bmain->name */
101 /* only for seq data */
102 struct BPathIteratorSeqData seqdata;
108 /* TODO - BPATH_PLUGIN, BPATH_SEQ */
122 void BLI_bpathIterator_init(struct BPathIterator **bpi_pt, Main *bmain, const char *basedir, const int flag)
126 bpi= MEM_mallocN(sizeof(BPathIterator), "BLI_bpathIterator_init");
129 bpi->type= BPATH_IMAGE;
132 bpi->getpath_callback= NULL;
133 bpi->setpath_callback= NULL;
135 /* Sequencer specific */
136 bpi->seqdata.totseq= 0;
138 bpi->seqdata.seqar= NULL;
139 bpi->seqdata.scene= NULL;
143 bpi->base_path= basedir; /* normally bmain->name */
146 BLI_bpathIterator_step(bpi);
150 static void BLI_bpathIterator_alloc(struct BPathIterator **bpi) {
151 *bpi= MEM_mallocN(sizeof(BPathIterator), "BLI_bpathIterator_alloc");
155 void BLI_bpathIterator_free(struct BPathIterator *bpi) {
156 if (bpi->seqdata.seqar)
157 MEM_freeN((void *)bpi->seqdata.seqar);
158 bpi->seqdata.seqar= NULL;
159 bpi->seqdata.scene= NULL;
164 void BLI_bpathIterator_getPath(struct BPathIterator *bpi, char *path) {
165 if (bpi->getpath_callback) {
166 bpi->getpath_callback(bpi, path);
168 strcpy(path, bpi->_path); /* warning, we assume 'path' are long enough */
172 void BLI_bpathIterator_setPath(struct BPathIterator *bpi, const char *path) {
173 if (bpi->setpath_callback) {
174 bpi->setpath_callback(bpi, path);
176 strcpy(bpi->_path, path); /* warning, we assume 'path' are long enough */
180 void BLI_bpathIterator_getPathExpanded(struct BPathIterator *bpi, char *path_expanded) {
183 BLI_bpathIterator_getPath(bpi, path_expanded);
184 libpath= BLI_bpathIterator_getLib(bpi);
186 if (libpath) { /* check the files location relative to its library path */
187 BLI_path_abs(path_expanded, libpath);
188 } else { /* local data, use the blend files path */
189 BLI_path_abs(path_expanded, bpi->base_path);
191 BLI_cleanup_file(NULL, path_expanded);
193 const char* BLI_bpathIterator_getLib(struct BPathIterator *bpi) {
196 const char* BLI_bpathIterator_getName(struct BPathIterator *bpi) {
199 int BLI_bpathIterator_getType(struct BPathIterator *bpi) {
202 unsigned int BLI_bpathIterator_getPathMaxLen(struct BPathIterator *bpi) {
205 const char* BLI_bpathIterator_getBasePath(struct BPathIterator *bpi) {
206 return bpi->base_path;
209 /* gets the first or the next image that has a path - not a viewer node or generated image */
210 static struct Image *ima_stepdata__internal(struct Image *ima, const int step_next, const int flag)
219 if (ELEM3(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
220 if(ima->packedfile==NULL || (flag & BPATH_USE_PACKED)) {
224 /* image is not a image with a path, skip it */
230 static struct Tex *tex_stepdata__internal(struct Tex *tex, const int step_next, const int UNUSED(flag))
239 if (tex->type == TEX_VOXELDATA && TEX_VD_IS_SOURCE_PATH(tex->vd->file_format))
241 /* image is not a image with a path, skip it */
247 static struct Text *text_stepdata__internal(struct Text *text, const int step_next, const int UNUSED(flag))
258 /* image is not a image with a path, skip it */
264 static struct VFont *vf_stepdata__internal(struct VFont *vf, const int step_next, const int flag)
273 if (strcmp(vf->name, FO_BUILTIN_NAME)!=0) {
274 if(vf->packedfile==NULL || (flag & BPATH_USE_PACKED)) {
279 /* font with no path, skip it */
285 static struct bSound *snd_stepdata__internal(struct bSound *snd, int step_next, const int flag)
294 if(snd->packedfile==NULL || (flag & BPATH_USE_PACKED)) {
298 /* font with no path, skip it */
304 static struct Sequence *seq_stepdata__internal(struct BPathIterator *bpi, int step_next)
310 if (bpi->seqdata.scene==NULL) {
311 bpi->seqdata.scene= bpi->bmain->scene.first;
318 while (bpi->seqdata.scene) {
319 ed= seq_give_editing(bpi->seqdata.scene, 0);
321 if (bpi->seqdata.seqar == NULL) {
322 /* allocate the sequencer array */
323 seq_array(ed, &bpi->seqdata.seqar, &bpi->seqdata.totseq, 0);
327 if (bpi->seqdata.seq >= bpi->seqdata.totseq) {
330 seq= bpi->seqdata.seqar[bpi->seqdata.seq];
331 while (!SEQ_HAS_PATH(seq) && seq->plugin==NULL) {
333 if (bpi->seqdata.seq >= bpi->seqdata.totseq) {
337 seq= bpi->seqdata.seqar[bpi->seqdata.seq];
343 /* keep looking through the next scene, reallocate seq array */
344 if (bpi->seqdata.seqar) {
345 MEM_freeN((void *)bpi->seqdata.seqar);
346 bpi->seqdata.seqar= NULL;
348 bpi->seqdata.scene= bpi->seqdata.scene->id.next;
351 /* no seq data in this scene, next */
352 bpi->seqdata.scene= bpi->seqdata.scene->id.next;
359 static void seq_getpath(struct BPathIterator *bpi, char *path) {
360 Sequence *seq= (Sequence *)bpi->data;
363 path[0]= '\0'; /* incase we cant get the path */
364 if (seq==NULL) return;
365 if (SEQ_HAS_PATH(seq)) {
366 if (ELEM3(seq->type, SEQ_IMAGE, SEQ_MOVIE, SEQ_SOUND)) {
367 BLI_strncpy(path, seq->strip->dir, FILE_MAX);
368 BLI_add_slash(path); /* incase its missing */
369 if (seq->strip->stripdata) { /* should always be true! */
370 /* Using the first image is weak for image sequences */
371 strcat(path, seq->strip->stripdata->name);
376 BLI_strncpy(seq->strip->dir, path, sizeof(seq->strip->dir));
379 else if (seq->plugin) {
380 BLI_strncpy(seq->plugin->name, path, sizeof(seq->plugin->name));
384 static void seq_setpath(struct BPathIterator *bpi, const char *path) {
385 Sequence *seq= (Sequence *)bpi->data;
386 if (seq==NULL) return;
388 if (SEQ_HAS_PATH(seq)) {
389 if (ELEM3(seq->type, SEQ_IMAGE, SEQ_MOVIE, SEQ_SOUND)) {
390 BLI_split_dirfile(path, seq->strip->dir, seq->strip->stripdata->name);
394 BLI_strncpy(seq->strip->dir, path, sizeof(seq->strip->dir));
397 else if (seq->plugin) {
398 BLI_strncpy(seq->plugin->name, path, sizeof(seq->plugin->name));
402 static void text_getpath(struct BPathIterator *bpi, char *path) {
403 Text *text= (Text *)bpi->data;
404 path[0]= '\0'; /* incase we cant get the path */
406 strcpy(path, text->name);
410 static void text_setpath(struct BPathIterator *bpi, const char *path) {
411 Text *text= (Text *)bpi->data;
412 if (text==NULL) return;
415 MEM_freeN(text->name);
418 text->name= BLI_strdup(path);
421 static struct Mesh *cdata_stepdata__internal(struct Mesh *me, int step_next) {
429 if (me->fdata.external) {
438 static void bpi_type_step__internal(struct BPathIterator *bpi) {
439 bpi->type++; /* advance to the next type */
444 bpi->getpath_callback= seq_getpath;
445 bpi->setpath_callback= seq_setpath;
447 case BPATH_TEXT: /* path is malloc'd */
448 bpi->getpath_callback= text_getpath;
449 bpi->setpath_callback= text_setpath;
452 bpi->getpath_callback= NULL;
453 bpi->setpath_callback= NULL;
458 void BLI_bpathIterator_step(struct BPathIterator *bpi) {
459 while (bpi->type != BPATH_DONE) {
461 if ((bpi->type) == BPATH_IMAGE) {
462 /*if (bpi->data) bpi->data= ((ID *)bpi->data)->next;*/
463 if (bpi->data) bpi->data= ima_stepdata__internal((Image *)bpi->data, 1, bpi->flag); /* must skip images that have no path */
464 else bpi->data= ima_stepdata__internal(bpi->bmain->image.first, 0, bpi->flag);
467 /* get the path info from this datatype */
468 Image *ima= (Image *)bpi->data;
470 bpi->_lib= ima->id.lib ? ima->id.lib->filepath : NULL;
471 bpi->_path= ima->name;
472 bpi->_name= ima->id.name+2;
473 bpi->len= sizeof(ima->name);
475 /* we are done, advancing to the next item, this type worked fine */
479 bpi_type_step__internal(bpi);
483 if ((bpi->type) == BPATH_TEXTURE) {
484 /*if (bpi->data) bpi->data= ((ID *)bpi->data)->next;*/
485 if (bpi->data) bpi->data= tex_stepdata__internal( (Tex *)bpi->data, 1, bpi->flag); /* must skip images that have no path */
486 else bpi->data= tex_stepdata__internal(bpi->bmain->tex.first, 0, bpi->flag);
489 /* get the path info from this datatype */
490 Tex *tex= (Tex *)bpi->data;
492 if(tex->type == TEX_VOXELDATA) {
493 bpi->_lib= tex->id.lib ? tex->id.lib->filepath : NULL;
494 bpi->_path= tex->vd->source_path;
495 bpi->_name= tex->id.name+2;
496 bpi->len= sizeof(tex->vd->source_path);
499 assert(!"Texture has no path, incorrect step 'tex_stepdata__internal'");
502 /* we are done, advancing to the next item, this type worked fine */
506 bpi_type_step__internal(bpi);
510 if ((bpi->type) == BPATH_TEXT) {
511 /*if (bpi->data) bpi->data= ((ID *)bpi->data)->next;*/
512 if (bpi->data) bpi->data= text_stepdata__internal((Text *)bpi->data, 1, bpi->flag); /* must skip images that have no path */
513 else bpi->data= text_stepdata__internal(bpi->bmain->text.first, 0, bpi->flag);
516 /* get the path info from this datatype */
517 Text *text= (Text *)bpi->data;
519 bpi->_lib= text->id.lib ? text->id.lib->filepath : NULL;
520 bpi->_path= NULL; /* bpi->path= text->name; */ /* get/set functions override. */
521 bpi->_name= text->id.name+2;
522 bpi->len= FILE_MAX; /* malloc'd but limit anyway since large paths may mess up other areas */
524 /* we are done, advancing to the next item, this type worked fine */
528 bpi_type_step__internal(bpi);
532 else if ((bpi->type) == BPATH_SOUND) {
533 if (bpi->data) bpi->data= snd_stepdata__internal((bSound *)bpi->data, 1, bpi->flag); /* must skip images that have no path */
534 else bpi->data= snd_stepdata__internal(bpi->bmain->sound.first, 0, bpi->flag);
537 /* get the path info from this datatype */
538 bSound *snd= (bSound *)bpi->data;
540 bpi->_lib= snd->id.lib ? snd->id.lib->filepath : NULL;
541 bpi->_path= snd->name;
542 bpi->_name= snd->id.name+2;
543 bpi->len= sizeof(snd->name);
545 /* we are done, advancing to the next item, this type worked fine */
548 bpi_type_step__internal(bpi);
552 } else if ((bpi->type) == BPATH_FONT) {
554 if (bpi->data) bpi->data= vf_stepdata__internal((VFont *)bpi->data, 1, bpi->flag);
555 else bpi->data= vf_stepdata__internal(bpi->bmain->vfont.first, 0, bpi->flag);
558 /* get the path info from this datatype */
559 VFont *vf= (VFont *)bpi->data;
561 bpi->_lib= vf->id.lib ? vf->id.lib->filepath : NULL;
562 bpi->_path= vf->name;
563 bpi->_name= vf->id.name+2;
564 bpi->len= sizeof(vf->name);
566 /* we are done, advancing to the next item, this type worked fine */
569 bpi_type_step__internal(bpi);
572 } else if ((bpi->type) == BPATH_LIB) {
573 if (bpi->data) bpi->data= ((ID *)bpi->data)->next;
574 else bpi->data= bpi->bmain->library.first;
577 /* get the path info from this datatype */
578 Library *lib= (Library *)bpi->data;
581 bpi->_path= lib->name;
583 bpi->len= sizeof(lib->name);
585 /* we are done, advancing to the next item, this type worked fine */
588 bpi_type_step__internal(bpi);
590 } else if ((bpi->type) == BPATH_SEQ) {
591 if (bpi->data) bpi->data= seq_stepdata__internal( bpi, 1 );
592 else bpi->data= seq_stepdata__internal( bpi, 0 );
594 Sequence *seq= (Sequence *)bpi->data;
596 bpi->_name= seq->name+2;
597 bpi->len= seq->plugin ? sizeof(seq->plugin->name) : sizeof(seq->strip->dir) + sizeof(seq->strip->stripdata->name);
600 bpi_type_step__internal(bpi);
602 } else if ((bpi->type) == BPATH_CDATA) {
603 if (bpi->data) bpi->data= cdata_stepdata__internal( bpi->data, 1 );
604 else bpi->data= cdata_stepdata__internal( bpi->bmain->mesh.first, 0 );
607 Mesh *me= (Mesh *)bpi->data;
608 bpi->_lib= me->id.lib ? me->id.lib->filepath : NULL;
609 bpi->_path= me->fdata.external->filename;
610 bpi->_name= me->id.name+2;
611 bpi->len= sizeof(me->fdata.external->filename);
614 bpi_type_step__internal(bpi);
620 int BLI_bpathIterator_isDone( struct BPathIterator *bpi) {
621 return bpi->type==BPATH_DONE;
624 /* include the path argument */
625 static void bpath_as_report(struct BPathIterator *bpi, const char *message, ReportList *reports)
629 char path_expanded[FILE_MAXDIR*2];
634 switch(BLI_bpathIterator_getType(bpi)) {
664 name= BLI_bpathIterator_getName(bpi);
665 BLI_bpathIterator_getPathExpanded(bpi, path_expanded);
668 if (name) BKE_reportf(reports, RPT_WARNING, "%s \"%s\", \"%s\": %s", prefix, name, path_expanded, message);
669 else BKE_reportf(reports, RPT_WARNING, "%s \"%s\": %s", prefix, path_expanded, message);
674 /* high level function */
675 void checkMissingFiles(Main *bmain, ReportList *reports) {
676 struct BPathIterator *bpi;
678 /* be sure there is low chance of the path being too short */
679 char filepath_expanded[FILE_MAXDIR*2];
681 BLI_bpathIterator_init(&bpi, bmain, bmain->name, 0);
682 while (!BLI_bpathIterator_isDone(bpi)) {
683 BLI_bpathIterator_getPathExpanded(bpi, filepath_expanded);
685 if (!BLI_exists(filepath_expanded))
686 bpath_as_report(bpi, "file not found", reports);
688 BLI_bpathIterator_step(bpi);
690 BLI_bpathIterator_free(bpi);
693 /* dont log any errors at the moment, should probably do this */
694 void makeFilesRelative(Main *bmain, const char *basedir, ReportList *reports) {
695 int tot= 0, changed= 0, failed= 0, linked= 0;
696 struct BPathIterator *bpi;
697 char filepath[FILE_MAX];
700 /* be sure there is low chance of the path being too short */
701 char filepath_relative[(FILE_MAXDIR * 2) + FILE_MAXFILE];
703 BLI_bpathIterator_init(&bpi, bmain, basedir, 0);
704 while (!BLI_bpathIterator_isDone(bpi)) {
705 BLI_bpathIterator_getPath(bpi, filepath);
706 libpath= BLI_bpathIterator_getLib(bpi);
708 if(strncmp(filepath, "//", 2)) {
709 if (libpath) { /* cant make relative if we are library - TODO, LOG THIS */
711 } else { /* local data, use the blend files path */
712 BLI_strncpy(filepath_relative, filepath, sizeof(filepath_relative));
713 /* Important BLI_cleanup_dir runs before the path is made relative
714 * because it wont work for paths that start with "//../" */
715 BLI_cleanup_file(bpi->base_path, filepath_relative); /* fix any /foo/../foo/ */
716 BLI_path_rel(filepath_relative, bpi->base_path);
717 /* be safe and check the length */
718 if (BLI_bpathIterator_getPathMaxLen(bpi) <= strlen(filepath_relative)) {
719 bpath_as_report(bpi, "couldn't make path relative (too long)", reports);
722 if(strncmp(filepath_relative, "//", 2)==0) {
723 BLI_bpathIterator_setPath(bpi, filepath_relative);
726 bpath_as_report(bpi, "couldn't make path relative", reports);
732 BLI_bpathIterator_step(bpi);
735 BLI_bpathIterator_free(bpi);
738 BKE_reportf(reports, failed ? RPT_ERROR : RPT_INFO, "Total files %i|Changed %i|Failed %i|Linked %i", tot, changed, failed, linked);
741 /* dont log any errors at the moment, should probably do this -
742 * Verry similar to makeFilesRelative - keep in sync! */
743 void makeFilesAbsolute(Main *bmain, const char *basedir, ReportList *reports)
745 int tot= 0, changed= 0, failed= 0, linked= 0;
747 struct BPathIterator *bpi;
748 char filepath[FILE_MAX];
751 /* be sure there is low chance of the path being too short */
752 char filepath_absolute[(FILE_MAXDIR * 2) + FILE_MAXFILE];
754 BLI_assert(basedir[0] != '\0');
756 BLI_bpathIterator_init(&bpi, bmain, basedir, 0);
757 while (!BLI_bpathIterator_isDone(bpi)) {
758 BLI_bpathIterator_getPath(bpi, filepath);
759 libpath= BLI_bpathIterator_getLib(bpi);
761 if(strncmp(filepath, "//", 2)==0) {
762 if (libpath) { /* cant make absolute if we are library - TODO, LOG THIS */
764 } else { /* get the expanded path and check it is relative or too long */
765 BLI_bpathIterator_getPathExpanded(bpi, filepath_absolute);
766 BLI_cleanup_file(bpi->base_path, filepath_absolute); /* fix any /foo/../foo/ */
767 /* to be safe, check the length */
768 if (BLI_bpathIterator_getPathMaxLen(bpi) <= strlen(filepath_absolute)) {
769 bpath_as_report(bpi, "couldn't make absolute (too long)", reports);
772 if(strncmp(filepath_absolute, "//", 2)) {
773 BLI_bpathIterator_setPath(bpi, filepath_absolute);
776 bpath_as_report(bpi, "couldn't make absolute", reports);
782 BLI_bpathIterator_step(bpi);
785 BLI_bpathIterator_free(bpi);
788 BKE_reportf(reports, failed ? RPT_ERROR : RPT_INFO, "Total files %i|Changed %i|Failed %i|Linked %i", tot, changed, failed, linked);
792 /* find this file recursively, use the biggest file so thumbnails dont get used by mistake
793 - dir: subdir to search
794 - filename: set this filename
795 - filesize: filesize for the file
798 static int findFileRecursive(char *filename_new, const char *dirname, const char *filename, int *filesize, int *recur_depth)
800 /* file searching stuff */
807 dir= opendir(dirname);
813 *filesize= 0; /* dir opened fine */
815 while ((de= readdir(dir)) != NULL) {
817 if (strcmp(".", de->d_name)==0 || strcmp("..", de->d_name)==0)
820 BLI_join_dirfile(path, sizeof(path), dirname, de->d_name);
822 if (stat(path, &status) != 0)
823 continue; /* cant stat, dont bother with this file, could print debug info here */
825 if (S_ISREG(status.st_mode)) { /* is file */
826 if (strncmp(filename, de->d_name, FILE_MAX)==0) { /* name matches */
827 /* open the file to read its size */
828 size= status.st_size;
829 if ((size > 0) && (size > *filesize)) { /* find the biggest file */
831 BLI_strncpy(filename_new, path, FILE_MAX);
834 } else if (S_ISDIR(status.st_mode)) { /* is subdir */
835 if (*recur_depth <= MAX_RECUR) {
837 findFileRecursive(filename_new, path, filename, filesize, recur_depth);
846 /* high level function - call from fileselector */
847 void findMissingFiles(Main *bmain, const char *str) {
848 struct BPathIterator *bpi;
850 /* be sure there is low chance of the path being too short */
851 char filepath_expanded[FILE_MAXDIR*2];
852 char filepath[FILE_MAX];
854 int filesize, recur_depth;
856 char dirname[FILE_MAX], filename_new[FILE_MAX];
858 //XXX waitcursor( 1 );
860 BLI_split_dirfile(str, dirname, NULL);
862 BLI_bpathIterator_init(&bpi, bmain, bmain->name, 0);
864 while (!BLI_bpathIterator_isDone(bpi)) {
865 BLI_bpathIterator_getPath(bpi, filepath);
866 libpath= BLI_bpathIterator_getLib(bpi);
868 /* Check if esc was pressed because searching files can be slow */
869 /*XXX if (blender_test_break()) {
875 BLI_bpathIterator_getPathExpanded(bpi, filepath_expanded);
877 if (!BLI_exists(filepath_expanded)) {
878 /* can the dir be opened? */
882 findFileRecursive(filename_new, dirname, BLI_path_basename(filepath), &filesize, &recur_depth);
883 if (filesize == -1) { /* could not open dir */
884 printf("Could not open dir \"%s\"\n", dirname);
890 if (BLI_bpathIterator_getPathMaxLen(bpi) < strlen(filename_new)) {
891 printf("cannot set path \"%s\" too long!", filename_new);
893 /* copy the found path into the old one */
895 BLI_path_rel(filename_new, bpi->base_path);
897 BLI_bpathIterator_setPath(bpi, filename_new);
902 BLI_bpathIterator_step(bpi);
904 BLI_bpathIterator_free(bpi);
906 //XXX waitcursor( 0 );