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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 *****
30 #include <sys/types.h>
38 /* path/file handeling stuff */
44 #include "BLI_winstuff.h"
47 #include "MEM_guardedalloc.h"
49 #include "DNA_ID.h" /* Library */
50 #include "DNA_vfont_types.h"
51 #include "DNA_image_types.h"
52 #include "DNA_sound_types.h"
53 #include "DNA_scene_types.h" /* to get the current frame */
54 #include "DNA_sequence_types.h"
55 #include "DNA_windowmanager_types.h"
57 #include "BLI_blenlib.h"
58 #include "BLI_bpath.h"
60 #include "BKE_global.h"
61 #include "BKE_image.h" /* so we can check the image's type */
62 #include "BKE_main.h" /* so we can access G.main->*.first */
63 #include "BKE_sequencer.h"
64 #include "BKE_utildefines.h"
65 #include "BKE_report.h"
67 //XXX #include "BIF_screen.h" /* only for wait cursor */
70 //XXX #include "BSE_sequence.h"
71 //XXX define below from BSE_sequence.h - otherwise potentially odd behaviour
72 #define SEQ_HAS_PATH(seq) (seq->type==SEQ_MOVIE || seq->type==SEQ_IMAGE)
78 /* TODO - BPATH_PLUGIN, BPATH_SEQ */
89 void BLI_bpathIterator_init( struct BPathIterator *bpi, char *base_path ) {
90 bpi->type = BPATH_IMAGE;
93 bpi->getpath_callback = NULL;
94 bpi->setpath_callback = NULL;
96 /* Sequencer specific */
97 bpi->seqdata.totseq = 0;
99 bpi->seqdata.seqar = NULL;
100 bpi->seqdata.scene = NULL;
102 bpi->base_path= base_path ? base_path : G.sce;
104 BLI_bpathIterator_step(bpi);
107 void BLI_bpathIterator_free( struct BPathIterator *bpi ) {
108 if (bpi->seqdata.seqar)
109 MEM_freeN((void *)bpi->seqdata.seqar);
110 bpi->seqdata.seqar = NULL;
111 bpi->seqdata.scene = NULL;
114 void BLI_bpathIterator_getPath( struct BPathIterator *bpi, char *path) {
115 if (bpi->getpath_callback) {
116 bpi->getpath_callback( bpi, path );
118 strcpy(path, bpi->path); /* warning, we assume 'path' are long enough */
122 void BLI_bpathIterator_setPath( struct BPathIterator *bpi, char *path) {
123 if (bpi->setpath_callback) {
124 bpi->setpath_callback( bpi, path );
126 strcpy(bpi->path, path); /* warning, we assume 'path' are long enough */
130 void BLI_bpathIterator_getPathExpanded( struct BPathIterator *bpi, char *path_expanded) {
133 BLI_bpathIterator_getPath(bpi, path_expanded);
134 libpath = BLI_bpathIterator_getLib(bpi);
136 if (libpath) { /* check the files location relative to its library path */
137 BLI_convertstringcode(path_expanded, libpath);
138 } else { /* local data, use the blend files path */
139 BLI_convertstringcode(path_expanded, bpi->base_path);
142 char* BLI_bpathIterator_getLib( struct BPathIterator *bpi) {
145 char* BLI_bpathIterator_getName( struct BPathIterator *bpi) {
148 int BLI_bpathIterator_getType( struct BPathIterator *bpi) {
151 int BLI_bpathIterator_getPathMaxLen( struct BPathIterator *bpi) {
155 /* gets the first or the next image that has a path - not a viewer node or generated image */
156 static struct Image *ima_stepdata__internal(struct Image *ima, int step_next) {
164 if (ima->packedfile==NULL && ELEM3(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE))
166 /* image is not a image with a path, skip it */
172 static struct VFont *vf_stepdata__internal(struct VFont *vf, int step_next) {
180 if (vf->packedfile==NULL && BLI_streq(vf->name, "<builtin>")==0) {
184 /* font with no path, skip it */
190 static struct bSound *snd_stepdata__internal(struct bSound *snd, int step_next) {
198 if (snd->packedfile==NULL) {
202 /* font with no path, skip it */
208 static struct Sequence *seq_stepdata__internal(struct BPathIterator *bpi, int step_next)
214 if (bpi->seqdata.scene==NULL) {
215 bpi->seqdata.scene= G.main->scene.first;
222 while (bpi->seqdata.scene) {
223 ed= seq_give_editing(bpi->seqdata.scene, 0);
225 if (bpi->seqdata.seqar == NULL) {
226 /* allocate the sequencer array */
227 seq_array(ed, &bpi->seqdata.seqar, &bpi->seqdata.totseq, 0);
228 bpi->seqdata.seq = 0;
231 if (bpi->seqdata.seq >= bpi->seqdata.totseq) {
234 seq = bpi->seqdata.seqar[bpi->seqdata.seq];
235 while (!SEQ_HAS_PATH(seq)) {
237 if (bpi->seqdata.seq >= bpi->seqdata.totseq) {
241 seq = bpi->seqdata.seqar[bpi->seqdata.seq];
247 /* keep looking through the next scene, reallocate seq array */
248 if (bpi->seqdata.seqar) {
249 MEM_freeN((void *)bpi->seqdata.seqar);
250 bpi->seqdata.seqar = NULL;
252 bpi->seqdata.scene = bpi->seqdata.scene->id.next;
255 /* no seq data in this scene, next */
256 bpi->seqdata.scene = bpi->seqdata.scene->id.next;
263 static void seq_getpath(struct BPathIterator *bpi, char *path) {
264 Sequence *seq = (Sequence *)bpi->data;
267 path[0] = '\0'; /* incase we cant get the path */
268 if (seq==NULL) return;
269 if (SEQ_HAS_PATH(seq)) {
270 if (seq->type == SEQ_IMAGE || seq->type == SEQ_MOVIE) {
271 BLI_strncpy(path, seq->strip->dir, FILE_MAX);
272 BLI_add_slash(path); /* incase its missing */
273 if (seq->strip->stripdata) { /* should always be true! */
274 /* Using the first image is weak for image sequences */
275 strcat(path, seq->strip->stripdata->name);
279 BLI_strncpy(seq->strip->dir, path, sizeof(seq->strip->dir));
284 static void seq_setpath(struct BPathIterator *bpi, char *path) {
285 Sequence *seq = (Sequence *)bpi->data;
286 if (seq==NULL) return;
288 if (SEQ_HAS_PATH(seq)) {
289 if (seq->type == SEQ_IMAGE || seq->type == SEQ_MOVIE) {
290 BLI_split_dirfile_basic(path, seq->strip->dir, seq->strip->stripdata->name);
293 BLI_strncpy(seq->strip->dir, path, sizeof(seq->strip->dir));
298 static void bpi_type_step__internal( struct BPathIterator *bpi) {
299 bpi->type++; /* advance to the next type */
304 bpi->getpath_callback = seq_getpath;
305 bpi->setpath_callback = seq_setpath;
308 bpi->getpath_callback = NULL;
309 bpi->setpath_callback = NULL;
314 void BLI_bpathIterator_step( struct BPathIterator *bpi) {
315 while (bpi->type != BPATH_DONE) {
317 if ((bpi->type) == BPATH_IMAGE) {
318 /*if (bpi->data) bpi->data = ((ID *)bpi->data)->next;*/
319 if (bpi->data) bpi->data = ima_stepdata__internal( (Image *)bpi->data, 1 ); /* must skip images that have no path */
320 else bpi->data = ima_stepdata__internal(G.main->image.first, 0);
323 /* get the path info from this datatype */
324 Image *ima = (Image *)bpi->data;
326 bpi->lib = ima->id.lib ? ima->id.lib->filename : NULL;
327 bpi->path = ima->name;
328 bpi->name = ima->id.name+2;
329 bpi->len = sizeof(ima->name);
331 /* we are done, advancing to the next item, this type worked fine */
335 bpi_type_step__internal(bpi);
339 } else if ((bpi->type) == BPATH_SOUND) {
340 if (bpi->data) bpi->data = snd_stepdata__internal( (bSound *)bpi->data, 1 ); /* must skip images that have no path */
341 else bpi->data = snd_stepdata__internal(G.main->sound.first, 0);
344 /* get the path info from this datatype */
345 bSound *snd = (bSound *)bpi->data;
347 bpi->lib = snd->id.lib ? snd->id.lib->filename : NULL;
348 bpi->path = snd->name;
349 bpi->name = snd->id.name+2;
350 bpi->len = sizeof(snd->name);
352 /* we are done, advancing to the next item, this type worked fine */
355 bpi_type_step__internal(bpi);
359 } else if ((bpi->type) == BPATH_FONT) {
361 if (bpi->data) bpi->data = vf_stepdata__internal( (VFont *)bpi->data, 1 );
362 else bpi->data = vf_stepdata__internal( G.main->vfont.first, 0 );
365 /* get the path info from this datatype */
366 VFont *vf = (VFont *)bpi->data;
368 bpi->lib = vf->id.lib ? vf->id.lib->filename : NULL;
369 bpi->path = vf->name;
370 bpi->name = vf->id.name+2;
371 bpi->len = sizeof(vf->name);
373 /* we are done, advancing to the next item, this type worked fine */
376 bpi_type_step__internal(bpi);
379 } else if ((bpi->type) == BPATH_LIB) {
380 if (bpi->data) bpi->data = ((ID *)bpi->data)->next;
381 else bpi->data = G.main->library.first;
384 /* get the path info from this datatype */
385 Library *lib = (Library *)bpi->data;
388 bpi->path = lib->name;
390 bpi->len = sizeof(lib->name);
392 /* we are done, advancing to the next item, this type worked fine */
395 bpi_type_step__internal(bpi);
397 } else if ((bpi->type) == BPATH_SEQ) {
398 if (bpi->data) bpi->data = seq_stepdata__internal( bpi, 1 );
399 else bpi->data = seq_stepdata__internal( bpi, 0 );
401 Sequence *seq = (Sequence *)bpi->data;
403 bpi->name = seq->name+2;
404 bpi->len = sizeof(seq->strip->stripdata->name);
407 bpi_type_step__internal(bpi);
413 int BLI_bpathIterator_isDone( struct BPathIterator *bpi) {
414 return bpi->type==BPATH_DONE;
417 /* include the path argument */
418 static void bpath_as_report(struct BPathIterator *bpi, const char *message, ReportList *reports)
422 char path_expanded[FILE_MAXDIR*2];
427 switch(BLI_bpathIterator_getType(bpi)) {
448 name = BLI_bpathIterator_getName(bpi);
449 BLI_bpathIterator_getPathExpanded(bpi, path_expanded);
452 if (name) BKE_reportf(reports, RPT_INFO, "%s \"%s\", \"%s\": %s", prefix, name, path_expanded, message);
453 else BKE_reportf(reports, RPT_INFO, "%s \"%s\": %s", prefix, path_expanded, message);
458 /* high level function */
459 void checkMissingFiles(char *basepath, ReportList *reports) {
460 struct BPathIterator bpi;
462 /* be sure there is low chance of the path being too short */
463 char filepath_expanded[FILE_MAXDIR*2];
465 BLI_bpathIterator_init(&bpi, basepath);
466 while (!BLI_bpathIterator_isDone(&bpi)) {
467 BLI_bpathIterator_getPathExpanded( &bpi, filepath_expanded );
469 if (!BLI_exists(filepath_expanded))
470 bpath_as_report(&bpi, "file not found", reports);
472 BLI_bpathIterator_step(&bpi);
474 BLI_bpathIterator_free(&bpi);
477 /* dont log any errors at the moment, should probably do this */
478 void makeFilesRelative(char *basepath, ReportList *reports) {
479 int tot= 0, changed= 0, failed= 0, linked= 0;
480 struct BPathIterator bpi;
481 char filepath[FILE_MAX], *libpath;
483 /* be sure there is low chance of the path being too short */
484 char filepath_relative[(FILE_MAXDIR * 2) + FILE_MAXFILE];
486 BLI_bpathIterator_init(&bpi, basepath);
487 while (!BLI_bpathIterator_isDone(&bpi)) {
488 BLI_bpathIterator_getPath(&bpi, filepath);
489 libpath = BLI_bpathIterator_getLib(&bpi);
491 if(strncmp(filepath, "//", 2)) {
492 if (libpath) { /* cant make relative if we are library - TODO, LOG THIS */
494 } else { /* local data, use the blend files path */
495 BLI_strncpy(filepath_relative, filepath, sizeof(filepath_relative));
496 /* Important BLI_cleanup_dir runs before the path is made relative
497 * because it wont work for paths that start with "//../" */
498 BLI_cleanup_file(bpi.base_path, filepath_relative); /* fix any /foo/../foo/ */
499 BLI_makestringcode(bpi.base_path, filepath_relative);
500 /* be safe and check the length */
501 if (BLI_bpathIterator_getPathMaxLen(&bpi) <= strlen(filepath_relative)) {
502 bpath_as_report(&bpi, "couldn't make path relative (too long)", reports);
505 if(strncmp(filepath_relative, "//", 2)==0) {
506 BLI_bpathIterator_setPath(&bpi, filepath_relative);
509 bpath_as_report(&bpi, "couldn't make path relative", reports);
515 BLI_bpathIterator_step(&bpi);
518 BLI_bpathIterator_free(&bpi);
521 BKE_reportf(reports, failed ? RPT_ERROR : RPT_INFO, "Total files %i|Changed %i|Failed %i|Linked %i", tot, changed, failed, linked);
524 /* dont log any errors at the moment, should probably do this -
525 * Verry similar to makeFilesRelative - keep in sync! */
526 void makeFilesAbsolute(char *basepath, ReportList *reports)
528 int tot= 0, changed= 0, failed= 0, linked= 0;
530 struct BPathIterator bpi;
531 char filepath[FILE_MAX], *libpath;
533 /* be sure there is low chance of the path being too short */
534 char filepath_absolute[(FILE_MAXDIR * 2) + FILE_MAXFILE];
536 BLI_bpathIterator_init(&bpi, basepath);
537 while (!BLI_bpathIterator_isDone(&bpi)) {
538 BLI_bpathIterator_getPath(&bpi, filepath);
539 libpath = BLI_bpathIterator_getLib(&bpi);
541 if(strncmp(filepath, "//", 2)==0) {
542 if (libpath) { /* cant make absolute if we are library - TODO, LOG THIS */
544 } else { /* get the expanded path and check it is relative or too long */
545 BLI_bpathIterator_getPathExpanded( &bpi, filepath_absolute );
546 BLI_cleanup_file(bpi.base_path, filepath_absolute); /* fix any /foo/../foo/ */
547 /* to be safe, check the length */
548 if (BLI_bpathIterator_getPathMaxLen(&bpi) <= strlen(filepath_absolute)) {
549 bpath_as_report(&bpi, "couldn't make absolute (too long)", reports);
552 if(strncmp(filepath_absolute, "//", 2)) {
553 BLI_bpathIterator_setPath(&bpi, filepath_absolute);
556 bpath_as_report(&bpi, "couldn't make absolute", reports);
562 BLI_bpathIterator_step(&bpi);
565 BLI_bpathIterator_free(&bpi);
568 BKE_reportf(reports, failed ? RPT_ERROR : RPT_INFO, "Total files %i|Changed %i|Failed %i|Linked %i", tot, changed, failed, linked);
572 /* find this file recursively, use the biggest file so thumbnails dont get used by mistake
573 - dir: subdir to search
574 - filename: set this filename
575 - filesize: filesize for the file
578 static int findFileRecursive(char *filename_new, const char *dirname, const char *filename, int *filesize, int *recur_depth)
580 /* file searching stuff */
587 dir = opendir(dirname);
593 *filesize = 0; /* dir opened fine */
595 while ((de = readdir(dir)) != NULL) {
597 if (strncmp(".", de->d_name, 2)==0 || strncmp("..", de->d_name, 3)==0)
600 BLI_join_dirfile(path, dirname, de->d_name);
602 if (stat(path, &status) != 0)
603 continue; /* cant stat, dont bother with this file, could print debug info here */
605 if (S_ISREG(status.st_mode)) { /* is file */
606 if (strncmp(filename, de->d_name, FILE_MAX)==0) { /* name matches */
607 /* open the file to read its size */
608 size = BLI_filepathsize(path);
609 if ((size > 0) && (size > *filesize)) { /* find the biggest file */
611 BLI_strncpy(filename_new, path, FILE_MAX);
614 } else if (S_ISDIR(status.st_mode)) { /* is subdir */
615 if (*recur_depth <= MAX_RECUR) {
617 findFileRecursive(filename_new, path, filename, filesize, recur_depth);
626 /* high level function - call from fileselector */
627 void findMissingFiles(char *basepath, char *str) {
628 struct BPathIterator bpi;
630 /* be sure there is low chance of the path being too short */
631 char filepath_expanded[FILE_MAXDIR*2];
632 char filepath[FILE_MAX], *libpath;
633 int filesize, recur_depth;
635 char dirname[FILE_MAX], filename[FILE_MAX], filename_new[FILE_MAX];
637 //XXX waitcursor( 1 );
639 BLI_split_dirfile_basic(str, dirname, NULL);
641 BLI_bpathIterator_init(&bpi, basepath);
643 while (!BLI_bpathIterator_isDone(&bpi)) {
644 BLI_bpathIterator_getPath(&bpi, filepath);
645 libpath = BLI_bpathIterator_getLib(&bpi);
647 /* Check if esc was pressed because searching files can be slow */
648 /*XXX if (blender_test_break()) {
654 BLI_bpathIterator_getPathExpanded( &bpi, filepath_expanded );
656 if (!BLI_exists(filepath_expanded)) {
657 /* can the dir be opened? */
660 BLI_split_dirfile_basic(filepath, NULL, filename); /* the file to find */
662 findFileRecursive(filename_new, dirname, filename, &filesize, &recur_depth);
663 if (filesize == -1) { /* could not open dir */
664 printf("Could not open dir \"%s\"\n", dirname);
670 if (BLI_bpathIterator_getPathMaxLen( &bpi ) < strlen(filename_new)) {
671 printf("cannot set path \"%s\" too long!", filename_new);
673 /* copy the found path into the old one */
675 BLI_makestringcode(bpi.base_path, filename_new);
677 BLI_bpathIterator_setPath( &bpi, filename_new );
682 BLI_bpathIterator_step(&bpi);
684 BLI_bpathIterator_free(&bpi);
686 //XXX waitcursor( 0 );