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 *****
29 #include "BLI_bpath.h"
30 #include "BKE_global.h"
31 #include "BIF_screen.h" /* only for wait cursor */
32 #include "DNA_ID.h" /* Library */
33 #include "DNA_vfont_types.h"
34 #include "DNA_image_types.h"
35 #include "DNA_sound_types.h"
36 #include "DNA_scene_types.h" /* to get the current frame */
37 #include "DNA_sequence_types.h"
41 #include "BKE_main.h" /* so we can access G.main->*.first */
42 #include "BKE_image.h" /* so we can check the image's type */
45 #include "BKE_utildefines.h"
46 #include "MEM_guardedalloc.h"
49 #include "BSE_sequence.h"
51 /* for writing to a textblock */
53 #include "BLI_blenlib.h"
54 #include "DNA_text_types.h"
56 /* path/file handeling stuff */
61 #include "BLI_winstuff.h"
66 #include <sys/types.h>
76 /* TODO - BPATH_PLUGIN, BPATH_SEQ */
87 void BLI_bpathIterator_init( struct BPathIterator *bpi ) {
88 bpi->type = BPATH_IMAGE;
91 bpi->getpath_callback = NULL;
92 bpi->setpath_callback = NULL;
94 /* Sequencer spesific */
95 bpi->seqdata.totseq = 0;
97 bpi->seqdata.seqar = NULL;
99 BLI_bpathIterator_step(bpi);
102 void BLI_bpathIterator_free( struct BPathIterator *bpi ) {
103 if (bpi->seqdata.seqar)
104 MEM_freeN((void *)bpi->seqdata.seqar);
105 bpi->seqdata.seqar = NULL;
108 void BLI_bpathIterator_getPath( struct BPathIterator *bpi, char *path) {
109 if (bpi->getpath_callback) {
110 bpi->getpath_callback( bpi, path );
112 strcpy(path, bpi->path); /* warning, we assume 'path' are long enough */
116 void BLI_bpathIterator_setPath( struct BPathIterator *bpi, char *path) {
117 if (bpi->setpath_callback) {
118 bpi->setpath_callback( bpi, path );
120 strcpy(bpi->path, path); /* warning, we assume 'path' are long enough */
124 void BLI_bpathIterator_getPathExpanded( struct BPathIterator *bpi, char *path_expanded) {
127 BLI_bpathIterator_getPath(bpi, path_expanded);
128 libpath = BLI_bpathIterator_getLib(bpi);
130 if (libpath) { /* check the files location relative to its library path */
131 BLI_convertstringcode(path_expanded, libpath, G.scene->r.cfra);
132 } else { /* local data, use the blend files path */
133 BLI_convertstringcode(path_expanded, G.sce, G.scene->r.cfra);
136 char* BLI_bpathIterator_getLib( struct BPathIterator *bpi) {
139 char* BLI_bpathIterator_getName( struct BPathIterator *bpi) {
142 int BLI_bpathIterator_getType( struct BPathIterator *bpi) {
145 int BLI_bpathIterator_getPathMaxLen( struct BPathIterator *bpi) {
149 /* gets the first or the next image that has a path - not a viewer node or generated image */
150 static struct Image *ima_stepdata__internal(struct Image *ima, int step_next) {
158 if (ima->packedfile==NULL && ELEM3(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE))
160 /* image is not a image with a path, skip it */
166 static struct VFont *vf_stepdata__internal(struct VFont *vf, int step_next) {
174 if (vf->packedfile==NULL && BLI_streq(vf->name, "<builtin>")==0) {
178 /* font with no path, skip it */
184 static struct bSound *snd_stepdata__internal(struct bSound *snd, int step_next) {
192 if (snd->packedfile==NULL) {
196 /* font with no path, skip it */
202 static struct Sequence *seq_stepdata__internal(struct BPathIterator *bpi, int step_next) {
205 if (G.scene->ed==NULL) {
209 if (bpi->seqdata.seqar == NULL) {
210 /* allocate the sequencer array */
211 build_seqar( &(((Editing *)G.scene->ed)->seqbase), &bpi->seqdata.seqar, &bpi->seqdata.totseq);
212 bpi->seqdata.seq = 0;
219 if (bpi->seqdata.seq >= bpi->seqdata.totseq) {
222 seq = bpi->seqdata.seqar[bpi->seqdata.seq];
223 while (!SEQ_HAS_PATH(seq)) {
225 if (bpi->seqdata.seq >= bpi->seqdata.totseq) {
229 seq = bpi->seqdata.seqar[bpi->seqdata.seq];
235 void seq_getpath(struct BPathIterator *bpi, char *path) {
236 Sequence *seq = (Sequence *)bpi->data;
239 path[0] = '\0'; /* incase we cant get the path */
240 if (seq==NULL) return;
241 if (SEQ_HAS_PATH(seq)) {
242 if (seq->type == SEQ_IMAGE || seq->type == SEQ_MOVIE) {
243 BLI_strncpy(path, seq->strip->dir, FILE_MAX);
244 BLI_add_slash(path); /* incase its missing */
245 if (seq->strip->stripdata) { /* should always be true! */
246 /* Using the first image is weak for image sequences */
247 strcat(path, seq->strip->stripdata->name);
251 BLI_strncpy(seq->strip->dir, path, sizeof(seq->strip->dir));
256 void seq_setpath(struct BPathIterator *bpi, char *path) {
257 Sequence *seq = (Sequence *)bpi->data;
258 if (seq==NULL) return;
260 if (SEQ_HAS_PATH(seq)) {
261 if (seq->type == SEQ_IMAGE || seq->type == SEQ_MOVIE) {
262 BLI_split_dirfile_basic(path, seq->strip->dir, seq->strip->stripdata->name);
265 BLI_strncpy(seq->strip->dir, path, sizeof(seq->strip->dir));
270 static void bpi_type_step__internal( struct BPathIterator *bpi) {
271 bpi->type++; /* advance to the next type */
276 bpi->getpath_callback = seq_getpath;
277 bpi->setpath_callback = seq_setpath;
280 bpi->getpath_callback = NULL;
281 bpi->setpath_callback = NULL;
286 void BLI_bpathIterator_step( struct BPathIterator *bpi) {
287 while (bpi->type != BPATH_DONE) {
289 if ((bpi->type) == BPATH_IMAGE) {
290 /*if (bpi->data) bpi->data = ((ID *)bpi->data)->next;*/
291 if (bpi->data) bpi->data = ima_stepdata__internal( (Image *)bpi->data, 1 ); /* must skip images that have no path */
292 else bpi->data = ima_stepdata__internal(G.main->image.first, 0);
295 /* get the path info from this datatype */
296 Image *ima = (Image *)bpi->data;
298 bpi->lib = ima->id.lib ? ima->id.lib->filename : NULL;
299 bpi->path = ima->name;
300 bpi->name = ima->id.name+2;
301 bpi->len = sizeof(ima->name);
303 /* we are done, advancing to the next item, this type worked fine */
307 bpi_type_step__internal(bpi);
311 } else if ((bpi->type) == BPATH_SOUND) {
312 if (bpi->data) bpi->data = snd_stepdata__internal( (bSound *)bpi->data, 1 ); /* must skip images that have no path */
313 else bpi->data = snd_stepdata__internal(G.main->sound.first, 0);
316 /* get the path info from this datatype */
317 bSound *snd = (bSound *)bpi->data;
319 bpi->lib = snd->id.lib ? snd->id.lib->filename : NULL;
320 bpi->path = snd->sample->name;
321 bpi->name = snd->id.name+2;
322 bpi->len = sizeof(snd->sample->name);
324 /* we are done, advancing to the next item, this type worked fine */
327 bpi_type_step__internal(bpi);
331 } else if ((bpi->type) == BPATH_FONT) {
333 if (bpi->data) bpi->data = vf_stepdata__internal( (VFont *)bpi->data, 1 );
334 else bpi->data = vf_stepdata__internal( G.main->vfont.first, 0 );
337 /* get the path info from this datatype */
338 VFont *vf = (VFont *)bpi->data;
340 bpi->lib = vf->id.lib ? vf->id.lib->filename : NULL;
341 bpi->path = vf->name;
342 bpi->name = vf->id.name+2;
343 bpi->len = sizeof(vf->name);
345 /* we are done, advancing to the next item, this type worked fine */
348 bpi_type_step__internal(bpi);
351 } else if ((bpi->type) == BPATH_LIB) {
352 if (bpi->data) bpi->data = ((ID *)bpi->data)->next;
353 else bpi->data = G.main->library.first;
356 /* get the path info from this datatype */
357 Library *lib = (Library *)bpi->data;
360 bpi->path = lib->name;
362 bpi->len = sizeof(lib->name);
364 /* we are done, advancing to the next item, this type worked fine */
367 bpi_type_step__internal(bpi);
369 } else if ((bpi->type) == BPATH_SEQ) {
370 if (bpi->data) bpi->data = seq_stepdata__internal( bpi, 1 );
371 else bpi->data = seq_stepdata__internal( bpi, 0 );
373 Sequence *seq = (Sequence *)bpi->data;
375 bpi->name = seq->name+2;
376 bpi->len = sizeof(seq->strip->stripdata->name);
379 bpi_type_step__internal(bpi);
385 int BLI_bpathIterator_isDone( struct BPathIterator *bpi) {
386 return bpi->type==BPATH_DONE;
389 /* include the path argument */
390 static void bpathToText(Text *btxt, struct BPathIterator *bpi)
393 char path_expanded[FILE_MAXDIR*2];
395 switch(BLI_bpathIterator_getType(bpi)) {
397 txt_insert_buf( btxt, "Image \"" );
400 txt_insert_buf( btxt, "Sound \"" );
403 txt_insert_buf( btxt, "Font \"" );
406 txt_insert_buf( btxt, "Library \"" );
409 txt_insert_buf( btxt, "Sequence \"" );
412 txt_insert_buf( btxt, "Unknown \"" );
416 name = BLI_bpathIterator_getName(bpi);
419 txt_insert_buf( btxt, name );
421 txt_insert_buf( btxt, "\" " );
423 BLI_bpathIterator_getPathExpanded(bpi, path_expanded);
425 txt_insert_buf( btxt, path_expanded );
426 txt_insert_buf( btxt, "\n" );
427 txt_move_eof( btxt, 0 );
430 /* high level function */
431 void checkMissingFiles( char *txtname ) {
433 struct BPathIterator bpi;
435 /* be sure there is low chance of the path being too short */
436 char filepath_expanded[FILE_MAXDIR*2];
438 int files_missing = 0;
440 BLI_bpathIterator_init(&bpi);
441 while (!BLI_bpathIterator_isDone(&bpi)) {
442 libpath = BLI_bpathIterator_getLib(&bpi);
444 BLI_bpathIterator_getPathExpanded( &bpi, filepath_expanded );
446 if (!BLI_exists(filepath_expanded)) {
448 btxt = add_empty_text( "missing_files.log" );
450 BLI_strncpy(txtname, btxt->id.name+2, 24);
453 bpathToText(btxt, &bpi);
456 BLI_bpathIterator_step(&bpi);
458 BLI_bpathIterator_free(&bpi);
461 /* dont log any errors at the moment, should probably do this */
462 void makeFilesRelative(char *txtname, int *tot, int *changed, int *failed, int *linked) {
463 struct BPathIterator bpi;
464 char filepath[FILE_MAX], *libpath;
466 /* be sure there is low chance of the path being too short */
467 char filepath_relative[(FILE_MAXDIR * 2) + FILE_MAXFILE];
471 *tot = *changed = *failed = *linked = 0;
473 BLI_bpathIterator_init(&bpi);
474 while (!BLI_bpathIterator_isDone(&bpi)) {
475 BLI_bpathIterator_getPath(&bpi, filepath);
476 libpath = BLI_bpathIterator_getLib(&bpi);
478 if(strncmp(filepath, "//", 2)) {
479 if (libpath) { /* cant make relative if we are library - TODO, LOG THIS */
481 } else { /* local data, use the blend files path */
482 BLI_strncpy(filepath_relative, filepath, sizeof(filepath_relative));
483 /* Important BLI_cleanup_dir runs before the path is made relative
484 * because it wont work for paths that start with "//../" */
485 BLI_cleanup_file(G.sce, filepath_relative); /* fix any /foo/../foo/ */
486 BLI_makestringcode(G.sce, filepath_relative);
487 /* be safe and check the length */
488 if (BLI_bpathIterator_getPathMaxLen(&bpi) <= strlen(filepath_relative)) {
490 btxt = add_empty_text( "missing_no_rel.log" );
492 BLI_strncpy(txtname, btxt->id.name+2, 24);
495 bpathToText(btxt, &bpi);
498 if(strncmp(filepath_relative, "//", 2)==0) {
499 BLI_bpathIterator_setPath(&bpi, filepath_relative);
503 btxt = add_empty_text( "missing_no_rel.log" );
505 BLI_strncpy(txtname, btxt->id.name+2, 24);
508 bpathToText(btxt, &bpi);
514 BLI_bpathIterator_step(&bpi);
517 BLI_bpathIterator_free(&bpi);
520 /* dont log any errors at the moment, should probably do this -
521 * Verry similar to makeFilesRelative - keep in sync! */
522 void makeFilesAbsolute(char *txtname, int *tot, int *changed, int *failed, int *linked) {
523 struct BPathIterator bpi;
524 char filepath[FILE_MAX], *libpath;
526 /* be sure there is low chance of the path being too short */
527 char filepath_absolute[(FILE_MAXDIR * 2) + FILE_MAXFILE];
531 *tot = *changed = *failed = *linked = 0;
533 BLI_bpathIterator_init(&bpi);
534 while (!BLI_bpathIterator_isDone(&bpi)) {
535 BLI_bpathIterator_getPath(&bpi, filepath);
536 libpath = BLI_bpathIterator_getLib(&bpi);
538 if(strncmp(filepath, "//", 2)==0) {
539 if (libpath) { /* cant make absolute if we are library - TODO, LOG THIS */
541 } else { /* get the expanded path and check it is relative or too long */
542 BLI_bpathIterator_getPathExpanded( &bpi, filepath_absolute );
543 BLI_cleanup_file(G.sce, filepath_absolute); /* fix any /foo/../foo/ */
544 /* to be safe, check the length */
545 if (BLI_bpathIterator_getPathMaxLen(&bpi) <= strlen(filepath_absolute)) {
547 btxt = add_empty_text( "missing_no_abs.log" );
549 BLI_strncpy(txtname, btxt->id.name+2, 24);
552 bpathToText(btxt, &bpi);
555 if(strncmp(filepath_absolute, "//", 2)) {
556 BLI_bpathIterator_setPath(&bpi, filepath_absolute);
560 btxt = add_empty_text( "missing_no_abs.log" );
562 BLI_strncpy(txtname, btxt->id.name+2, 24);
565 bpathToText(btxt, &bpi);
571 BLI_bpathIterator_step(&bpi);
574 BLI_bpathIterator_free(&bpi);
578 /* find this file recursively, use the biggest file so thumbnails dont get used by mistake
579 - dir: subdir to search
580 - filename: set this filename
581 - filesize: filesize for the file
584 static int findFileRecursive(char *filename_new, const char *dirname, const char *filename, int *filesize, int *recur_depth)
586 /* file searching stuff */
593 dir = opendir(dirname);
599 *filesize = 0; /* dir opened fine */
601 while ((de = readdir(dir)) != NULL) {
603 if (strncmp(".", de->d_name, 2)==0 || strncmp("..", de->d_name, 3)==0)
606 BLI_join_dirfile(path, dirname, de->d_name);
608 if (stat(path, &status) != 0)
609 continue; /* cant stat, dont bother with this file, could print debug info here */
611 if (S_ISREG(status.st_mode)) { /* is file */
612 if (strncmp(filename, de->d_name, FILE_MAX)==0) { /* name matches */
613 /* open the file to read its size */
614 size = BLI_filepathsize(path);
615 if ((size > 0) && (size > *filesize)) { /* find the biggest file */
617 BLI_strncpy(filename_new, path, FILE_MAX);
620 } else if (S_ISDIR(status.st_mode)) { /* is subdir */
621 if (*recur_depth <= MAX_RECUR) {
623 findFileRecursive(filename_new, path, filename, filesize, recur_depth);
632 /* high level function - call from fileselector */
633 void findMissingFiles(char *str) {
634 struct BPathIterator bpi;
636 /* be sure there is low chance of the path being too short */
637 char filepath_expanded[FILE_MAXDIR*2];
638 char filepath[FILE_MAX], *libpath;
639 int filesize, recur_depth;
641 char dirname[FILE_MAX], filename[FILE_MAX], filename_new[FILE_MAX], dummyname[FILE_MAX];
645 BLI_split_dirfile_basic(str, dirname, NULL);
647 BLI_bpathIterator_init(&bpi);
649 while (!BLI_bpathIterator_isDone(&bpi)) {
650 BLI_bpathIterator_getPath(&bpi, filepath);
651 libpath = BLI_bpathIterator_getLib(&bpi);
653 /* Check if esc was pressed because searching files can be slow */
654 if (blender_test_break()) {
660 BLI_bpathIterator_getPathExpanded( &bpi, filepath_expanded );
662 if (!BLI_exists(filepath_expanded)) {
663 /* can the dir be opened? */
666 BLI_split_dirfile_basic(filepath, NULL, filename); /* the file to find */
668 findFileRecursive(filename_new, dirname, filename, &filesize, &recur_depth);
669 if (filesize == -1) { /* could not open dir */
670 printf("Could not open dir \"%s\"\n", dirname);
676 if (BLI_bpathIterator_getPathMaxLen( &bpi ) < strlen(filename_new)) {
677 printf("cannot set path \"%s\" too long!", filename_new);
679 /* copy the found path into the old one */
681 BLI_makestringcode(G.sce, filename_new);
683 BLI_bpathIterator_setPath( &bpi, filename_new );
688 BLI_bpathIterator_step(&bpi);
690 BLI_bpathIterator_free(&bpi);