~ubuntu-branches/ubuntu/trusty/blender/trusty

« back to all changes in this revision

Viewing changes to source/blender/blenkernel/intern/bpath.c

  • Committer: Package Import Robot
  • Author(s): Jeremy Bicha
  • Date: 2013-03-06 12:08:47 UTC
  • mfrom: (1.5.1) (14.1.8 experimental)
  • Revision ID: package-import@ubuntu.com-20130306120847-frjfaryb2zrotwcg
Tags: 2.66a-1ubuntu1
* Resynchronize with Debian (LP: #1076930, #1089256, #1052743, #999024,
  #1122888, #1147084)
* debian/control:
  - Lower build-depends on libavcodec-dev since we're not
    doing the libav9 transition in Ubuntu yet

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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, Alex Fraser
 
24
 *
 
25
 * ***** END GPL LICENSE BLOCK *****
 
26
 */
 
27
 
 
28
/** \file blender/blenkernel/intern/bpath.c
 
29
 *  \ingroup bli
 
30
 */
 
31
 
 
32
/* TODO,
 
33
 * currently there are some cases we don't support.
 
34
 * - passing output paths to the visitor?, like render out.
 
35
 * - passing sequence strips with many images.
 
36
 * - passing directory paths - visitors don't know which path is a dir or a file.
 
37
 * */
 
38
 
 
39
#include <sys/stat.h>
 
40
 
 
41
#include <string.h>
 
42
#include <assert.h>
 
43
 
 
44
/* path/file handling stuff */
 
45
#ifndef WIN32
 
46
#  include <dirent.h>
 
47
#  include <unistd.h>
 
48
#else
 
49
#  include <io.h>
 
50
#  include "BLI_winstuff.h"
 
51
#endif
 
52
 
 
53
#include "MEM_guardedalloc.h"
 
54
 
 
55
#include "DNA_brush_types.h"
 
56
#include "DNA_image_types.h"
 
57
#include "DNA_mesh_types.h"
 
58
#include "DNA_modifier_types.h"
 
59
#include "DNA_movieclip_types.h"
 
60
#include "DNA_object_fluidsim.h"
 
61
#include "DNA_object_force.h"
 
62
#include "DNA_object_types.h"
 
63
#include "DNA_particle_types.h"
 
64
#include "DNA_sequence_types.h"
 
65
#include "DNA_sound_types.h"
 
66
#include "DNA_text_types.h"
 
67
#include "DNA_material_types.h"
 
68
#include "DNA_node_types.h"
 
69
#include "DNA_texture_types.h"
 
70
#include "DNA_vfont_types.h"
 
71
#include "DNA_scene_types.h"
 
72
#include "DNA_smoke_types.h"
 
73
 
 
74
#include "BLI_blenlib.h"
 
75
#include "BLI_utildefines.h"
 
76
 
 
77
#include "BKE_font.h"
 
78
#include "BKE_library.h"
 
79
#include "BKE_main.h"
 
80
#include "BKE_node.h"
 
81
#include "BKE_report.h"
 
82
#include "BKE_sequencer.h"
 
83
#include "BKE_image.h" /* so we can check the image's type */
 
84
 
 
85
#include "BKE_bpath.h"  /* own include */
 
86
 
 
87
static int checkMissingFiles_visit_cb(void *userdata, char *UNUSED(path_dst), const char *path_src)
 
88
{
 
89
        ReportList *reports = (ReportList *)userdata;
 
90
 
 
91
        if (!BLI_exists(path_src)) {
 
92
                BKE_reportf(reports, RPT_WARNING, "Path '%s' not found", path_src);
 
93
        }
 
94
 
 
95
        return FALSE;
 
96
}
 
97
 
 
98
/* high level function */
 
99
void BKE_bpath_missing_files_check(Main *bmain, ReportList *reports)
 
100
{
 
101
        BKE_bpath_traverse_main(bmain, checkMissingFiles_visit_cb, BKE_BPATH_TRAVERSE_ABS, reports);
 
102
}
 
103
 
 
104
typedef struct BPathRemap_Data {
 
105
        const char *basedir;
 
106
        ReportList *reports;
 
107
 
 
108
        int count_tot;
 
109
        int count_changed;
 
110
        int count_failed;
 
111
} BPathRemap_Data;
 
112
 
 
113
static int makeFilesRelative_visit_cb(void *userdata, char *path_dst, const char *path_src)
 
114
{
 
115
        BPathRemap_Data *data = (BPathRemap_Data *)userdata;
 
116
 
 
117
        data->count_tot++;
 
118
 
 
119
        if (BLI_path_is_rel(path_src)) {
 
120
                return FALSE; /* already relative */
 
121
        }
 
122
        else {
 
123
                strcpy(path_dst, path_src);
 
124
                BLI_path_rel(path_dst, data->basedir);
 
125
                if (BLI_path_is_rel(path_dst)) {
 
126
                        data->count_changed++;
 
127
                }
 
128
                else {
 
129
                        BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made relative", path_src);
 
130
                        data->count_failed++;
 
131
                }
 
132
                return TRUE;
 
133
        }
 
134
}
 
135
 
 
136
void BKE_bpath_relative_convert(Main *bmain, const char *basedir, ReportList *reports)
 
137
{
 
138
        BPathRemap_Data data = {NULL};
 
139
 
 
140
        if (basedir[0] == '\0') {
 
141
                printf("%s: basedir='', this is a bug\n", __func__);
 
142
                return;
 
143
        }
 
144
 
 
145
        data.basedir = basedir;
 
146
        data.reports = reports;
 
147
 
 
148
        BKE_bpath_traverse_main(bmain, makeFilesRelative_visit_cb, 0, (void *)&data);
 
149
 
 
150
        BKE_reportf(reports, data.count_failed ? RPT_WARNING : RPT_INFO,
 
151
                    "Total files %d | Changed %d | Failed %d",
 
152
                    data.count_tot, data.count_changed, data.count_failed);
 
153
}
 
154
 
 
155
static int makeFilesAbsolute_visit_cb(void *userdata, char *path_dst, const char *path_src)
 
156
{
 
157
        BPathRemap_Data *data = (BPathRemap_Data *)userdata;
 
158
 
 
159
        data->count_tot++;
 
160
 
 
161
        if (BLI_path_is_rel(path_src) == FALSE) {
 
162
                return FALSE; /* already absolute */
 
163
        }
 
164
        else {
 
165
                strcpy(path_dst, path_src);
 
166
                BLI_path_abs(path_dst, data->basedir);
 
167
                if (BLI_path_is_rel(path_dst) == FALSE) {
 
168
                        data->count_changed++;
 
169
                }
 
170
                else {
 
171
                        BKE_reportf(data->reports, RPT_WARNING, "Path '%s' cannot be made absolute", path_src);
 
172
                        data->count_failed++;
 
173
                }
 
174
                return TRUE;
 
175
        }
 
176
}
 
177
 
 
178
/* similar to BKE_bpath_relative_convert - keep in sync! */
 
179
void BKE_bpath_absolute_convert(Main *bmain, const char *basedir, ReportList *reports)
 
180
{
 
181
        BPathRemap_Data data = {NULL};
 
182
 
 
183
        if (basedir[0] == '\0') {
 
184
                printf("%s: basedir='', this is a bug\n", __func__);
 
185
                return;
 
186
        }
 
187
 
 
188
        data.basedir = basedir;
 
189
        data.reports = reports;
 
190
 
 
191
        BKE_bpath_traverse_main(bmain, makeFilesAbsolute_visit_cb, 0, (void *)&data);
 
192
 
 
193
        BKE_reportf(reports, data.count_failed ? RPT_WARNING : RPT_INFO,
 
194
                    "Total files %d | Changed %d | Failed %d",
 
195
                    data.count_tot, data.count_changed, data.count_failed);
 
196
}
 
197
 
 
198
/**
 
199
 * find this file recursively, use the biggest file so thumbnails don't get used by mistake
 
200
 * \param filename_new: the path will be copied here, caller must initialize as empty string.
 
201
 * \param dirname: subdir to search
 
202
 * \param filename: set this filename
 
203
 * \param filesize: filesize for the file
 
204
 *
 
205
 * \returns found: 1/0.
 
206
 */
 
207
#define MAX_RECUR 16
 
208
static int findFileRecursive(char *filename_new,
 
209
                             const char *dirname,
 
210
                             const char *filename,
 
211
                             int *filesize,
 
212
                             int *recur_depth)
 
213
{
 
214
        /* file searching stuff */
 
215
        DIR *dir;
 
216
        struct dirent *de;
 
217
        struct stat status;
 
218
        char path[FILE_MAX];
 
219
        int size;
 
220
        int found = FALSE;
 
221
 
 
222
        dir = opendir(dirname);
 
223
 
 
224
        if (dir == NULL)
 
225
                return found;
 
226
 
 
227
        if (*filesize == -1)
 
228
                *filesize = 0;  /* dir opened fine */
 
229
 
 
230
        while ((de = readdir(dir)) != NULL) {
 
231
 
 
232
                if (strcmp(".", de->d_name) == 0 || strcmp("..", de->d_name) == 0)
 
233
                        continue;
 
234
 
 
235
                BLI_join_dirfile(path, sizeof(path), dirname, de->d_name);
 
236
 
 
237
                if (stat(path, &status) != 0)
 
238
                        continue;  /* cant stat, don't bother with this file, could print debug info here */
 
239
 
 
240
                if (S_ISREG(status.st_mode)) { /* is file */
 
241
                        if (strncmp(filename, de->d_name, FILE_MAX) == 0) { /* name matches */
 
242
                                /* open the file to read its size */
 
243
                                size = status.st_size;
 
244
                                if ((size > 0) && (size > *filesize)) { /* find the biggest file */
 
245
                                        *filesize = size;
 
246
                                        BLI_strncpy(filename_new, path, FILE_MAX);
 
247
                                        found = TRUE;
 
248
                                }
 
249
                        }
 
250
                }
 
251
                else if (S_ISDIR(status.st_mode)) { /* is subdir */
 
252
                        if (*recur_depth <= MAX_RECUR) {
 
253
                                (*recur_depth)++;
 
254
                                found |= findFileRecursive(filename_new, path, filename, filesize, recur_depth);
 
255
                                (*recur_depth)--;
 
256
                        }
 
257
                }
 
258
        }
 
259
        closedir(dir);
 
260
        return found;
 
261
}
 
262
 
 
263
typedef struct BPathFind_Data {
 
264
        const char *basedir;
 
265
        char searchdir[FILE_MAX];
 
266
        ReportList *reports;
 
267
} BPathFind_Data;
 
268
 
 
269
static int findMissingFiles_visit_cb(void *userdata, char *path_dst, const char *path_src)
 
270
{
 
271
        BPathFind_Data *data = (BPathFind_Data *)userdata;
 
272
        char filename_new[FILE_MAX];
 
273
 
 
274
        int filesize = -1;
 
275
        int recur_depth = 0;
 
276
        int found;
 
277
 
 
278
        filename_new[0] = '\0';
 
279
 
 
280
        found = findFileRecursive(filename_new,
 
281
                                  data->searchdir, BLI_path_basename((char *)path_src),
 
282
                                  &filesize, &recur_depth);
 
283
 
 
284
        if (filesize == -1) { /* could not open dir */
 
285
                BKE_reportf(data->reports, RPT_WARNING,
 
286
                            "Could not open directory '%s'",
 
287
                            BLI_path_basename(data->searchdir));
 
288
                return FALSE;
 
289
        }
 
290
        else if (found == FALSE) {
 
291
                BKE_reportf(data->reports, RPT_WARNING,
 
292
                            "Could not find '%s' in '%s'",
 
293
                            BLI_path_basename((char *)path_src), data->searchdir);
 
294
                return FALSE;
 
295
        }
 
296
        else {
 
297
                BLI_strncpy(path_dst, filename_new, FILE_MAX);
 
298
                return TRUE;
 
299
        }
 
300
}
 
301
 
 
302
void BKE_bpath_missing_files_find(Main *bmain, const char *searchpath, ReportList *reports)
 
303
{
 
304
        struct BPathFind_Data data = {NULL};
 
305
 
 
306
        data.reports = reports;
 
307
        BLI_split_dir_part(searchpath, data.searchdir, sizeof(data.searchdir));
 
308
 
 
309
        BKE_bpath_traverse_main(bmain, findMissingFiles_visit_cb, 0, (void *)&data);
 
310
}
 
311
 
 
312
/* Run a visitor on a string, replacing the contents of the string as needed. */
 
313
static int rewrite_path_fixed(char *path, BPathVisitor visit_cb, const char *absbase, void *userdata)
 
314
{
 
315
        char path_src_buf[FILE_MAX];
 
316
        const char *path_src;
 
317
        char path_dst[FILE_MAX];
 
318
 
 
319
        if (absbase) {
 
320
                BLI_strncpy(path_src_buf, path, sizeof(path_src_buf));
 
321
                BLI_path_abs(path_src_buf, absbase);
 
322
                path_src = path_src_buf;
 
323
        }
 
324
        else {
 
325
                path_src = path;
 
326
        }
 
327
 
 
328
        if (visit_cb(userdata, path_dst, path_src)) {
 
329
                BLI_strncpy(path, path_dst, FILE_MAX);
 
330
                return TRUE;
 
331
        }
 
332
        else {
 
333
                return FALSE;
 
334
        }
 
335
}
 
336
 
 
337
static int rewrite_path_fixed_dirfile(char path_dir[FILE_MAXDIR],
 
338
                                      char path_file[FILE_MAXFILE],
 
339
                                      BPathVisitor visit_cb,
 
340
                                      const char *absbase,
 
341
                                      void *userdata)
 
342
{
 
343
        char path_src[FILE_MAX];
 
344
        char path_dst[FILE_MAX];
 
345
 
 
346
        BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file);
 
347
 
 
348
        if (absbase) {
 
349
                BLI_path_abs(path_src, absbase);
 
350
        }
 
351
 
 
352
        if (visit_cb(userdata, path_dst, (const char *)path_src)) {
 
353
                BLI_split_dirfile(path_dst, path_dir, path_file, FILE_MAXDIR, FILE_MAXFILE);
 
354
                return TRUE;
 
355
        }
 
356
        else {
 
357
                return FALSE;
 
358
        }
 
359
}
 
360
 
 
361
static int rewrite_path_alloc(char **path, BPathVisitor visit_cb, const char *absbase, void *userdata)
 
362
{
 
363
        char path_src_buf[FILE_MAX];
 
364
        const char *path_src;
 
365
        char path_dst[FILE_MAX];
 
366
 
 
367
        if (absbase) {
 
368
                BLI_strncpy(path_src_buf, *path, sizeof(path_src_buf));
 
369
                BLI_path_abs(path_src_buf, absbase);
 
370
                path_src = path_src_buf;
 
371
        }
 
372
        else {
 
373
                path_src = *path;
 
374
        }
 
375
 
 
376
        if (visit_cb(userdata, path_dst, path_src)) {
 
377
                MEM_freeN((*path));
 
378
                (*path) = BLI_strdup(path_dst);
 
379
                return TRUE;
 
380
        }
 
381
        else {
 
382
                return FALSE;
 
383
        }
 
384
}
 
385
 
 
386
/* Run visitor function 'visit' on all paths contained in 'id'. */
 
387
void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int flag, void *bpath_user_data)
 
388
{
 
389
        const char *absbase = (flag & BKE_BPATH_TRAVERSE_ABS) ? ID_BLEND_PATH(bmain, id) : NULL;
 
390
 
 
391
        if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && id->lib) {
 
392
                return;
 
393
        }
 
394
 
 
395
        switch (GS(id->name)) {
 
396
                case ID_IM:
 
397
                {
 
398
                        Image *ima;
 
399
                        ima = (Image *)id;
 
400
                        if (ima->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
 
401
                                if (ELEM3(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) {
 
402
                                        rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data);
 
403
                                }
 
404
                        }
 
405
                        break;
 
406
                }
 
407
                case ID_BR:
 
408
                {
 
409
                        Brush *brush = (Brush *)id;
 
410
                        if (brush->icon_filepath[0]) {
 
411
                                rewrite_path_fixed(brush->icon_filepath, visit_cb, absbase, bpath_user_data);
 
412
                        }
 
413
                        break;
 
414
                }
 
415
                case ID_OB:
 
416
                {
 
417
                        Object *ob = (Object *)id;
 
418
                        ModifierData *md;
 
419
                        ParticleSystem *psys;
 
420
 
 
421
#define BPATH_TRAVERSE_POINTCACHE(ptcaches)                                    \
 
422
        {                                                                          \
 
423
                PointCache *cache;                                                     \
 
424
                for (cache = (ptcaches).first; cache; cache = cache->next) {           \
 
425
                        if (cache->flag & PTCACHE_DISK_CACHE) {                            \
 
426
                                rewrite_path_fixed(cache->path,                                \
 
427
                                                   visit_cb,                                   \
 
428
                                                   absbase,                                    \
 
429
                                                   bpath_user_data);                           \
 
430
                        }                                                                  \
 
431
                }                                                                      \
 
432
        } (void)0
 
433
 
 
434
                        /* do via modifiers instead */
 
435
#if 0
 
436
                        if (ob->fluidsimSettings) {
 
437
                                rewrite_path_fixed(ob->fluidsimSettings->surfdataPath, visit_cb, absbase, bpath_user_data);
 
438
                        }
 
439
#endif
 
440
 
 
441
                        for (md = ob->modifiers.first; md; md = md->next) {
 
442
                                if (md->type == eModifierType_Fluidsim) {
 
443
                                        FluidsimModifierData *fluidmd = (FluidsimModifierData *)md;
 
444
                                        if (fluidmd->fss) {
 
445
                                                rewrite_path_fixed(fluidmd->fss->surfdataPath, visit_cb, absbase, bpath_user_data);
 
446
                                        }
 
447
                                }
 
448
                                else if (md->type == eModifierType_Smoke) {
 
449
                                        SmokeModifierData *smd = (SmokeModifierData *)md;
 
450
                                        if (smd->type & MOD_SMOKE_TYPE_DOMAIN) {
 
451
                                                BPATH_TRAVERSE_POINTCACHE(smd->domain->ptcaches[0]);
 
452
                                        }
 
453
                                }
 
454
                                else if (md->type == eModifierType_Cloth) {
 
455
                                        ClothModifierData *clmd = (ClothModifierData *) md;
 
456
                                        BPATH_TRAVERSE_POINTCACHE(clmd->ptcaches);
 
457
                                }
 
458
                                else if (md->type == eModifierType_Ocean) {
 
459
                                        OceanModifierData *omd = (OceanModifierData *) md;
 
460
                                        rewrite_path_fixed(omd->cachepath, visit_cb, absbase, bpath_user_data);
 
461
                                }
 
462
                                else if (md->type == eModifierType_MeshCache) {
 
463
                                        MeshCacheModifierData *mcmd = (MeshCacheModifierData *) md;
 
464
                                        rewrite_path_fixed(mcmd->filepath, visit_cb, absbase, bpath_user_data);
 
465
                                }
 
466
                        }
 
467
 
 
468
                        if (ob->soft) {
 
469
                                BPATH_TRAVERSE_POINTCACHE(ob->soft->ptcaches);
 
470
                        }
 
471
 
 
472
                        for (psys = ob->particlesystem.first; psys; psys = psys->next) {
 
473
                                BPATH_TRAVERSE_POINTCACHE(psys->ptcaches);
 
474
                        }
 
475
 
 
476
#undef BPATH_TRAVERSE_POINTCACHE
 
477
 
 
478
                        break;
 
479
                }
 
480
                case ID_SO:
 
481
                {
 
482
                        bSound *sound = (bSound *)id;
 
483
                        if (sound->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
 
484
                                rewrite_path_fixed(sound->name, visit_cb, absbase, bpath_user_data);
 
485
                        }
 
486
                        break;
 
487
                }
 
488
                case ID_TXT:
 
489
                        if (((Text *)id)->name) {
 
490
                                rewrite_path_alloc(&((Text *)id)->name, visit_cb, absbase, bpath_user_data);
 
491
                        }
 
492
                        break;
 
493
                case ID_VF:
 
494
                {
 
495
                        VFont *vfont = (VFont *)id;
 
496
                        if (vfont->packedfile == NULL || (flag & BKE_BPATH_TRAVERSE_SKIP_PACKED) == 0) {
 
497
                                if (BKE_vfont_is_builtin(vfont) == FALSE) {
 
498
                                        rewrite_path_fixed(((VFont *)id)->name, visit_cb, absbase, bpath_user_data);
 
499
                                }
 
500
                        }
 
501
                        break;
 
502
                }
 
503
                case ID_MA:
 
504
                {
 
505
                        Material *ma = (Material *)id;
 
506
                        bNodeTree *ntree = ma->nodetree;
 
507
 
 
508
                        if (ntree) {
 
509
                                bNode *node;
 
510
 
 
511
                                for (node = ntree->nodes.first; node; node = node->next) {
 
512
                                        if (node->type == SH_NODE_SCRIPT) {
 
513
                                                NodeShaderScript *nss = (NodeShaderScript *)node->storage;
 
514
                                                rewrite_path_fixed(nss->filepath, visit_cb, absbase, bpath_user_data);
 
515
                                        }
 
516
                                }
 
517
                        }
 
518
                        break;
 
519
                }
 
520
                case ID_NT:
 
521
                {
 
522
                        bNodeTree *ntree = (bNodeTree *)id;
 
523
                        bNode *node;
 
524
 
 
525
                        if (ntree->type == NTREE_SHADER) {
 
526
                                /* same as lines above */
 
527
                                for (node = ntree->nodes.first; node; node = node->next) {
 
528
                                        if (node->type == SH_NODE_SCRIPT) {
 
529
                                                NodeShaderScript *nss = (NodeShaderScript *)node->storage;
 
530
                                                rewrite_path_fixed(nss->filepath, visit_cb, absbase, bpath_user_data);
 
531
                                        }
 
532
                                }
 
533
                        }
 
534
                        break;
 
535
                }
 
536
                case ID_TE:
 
537
                {
 
538
                        Tex *tex = (Tex *)id;
 
539
                        if (tex->type == TEX_VOXELDATA && TEX_VD_IS_SOURCE_PATH(tex->vd->file_format)) {
 
540
                                rewrite_path_fixed(tex->vd->source_path, visit_cb, absbase, bpath_user_data);
 
541
                        }
 
542
                        break;
 
543
                }
 
544
                case ID_SCE:
 
545
                {
 
546
                        Scene *scene = (Scene *)id;
 
547
                        if (scene->ed) {
 
548
                                Sequence *seq;
 
549
 
 
550
                                SEQ_BEGIN(scene->ed, seq)
 
551
                                {
 
552
                                        if (SEQ_HAS_PATH(seq)) {
 
553
                                                if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM)) {
 
554
                                                        rewrite_path_fixed_dirfile(seq->strip->dir, seq->strip->stripdata->name,
 
555
                                                                                   visit_cb, absbase, bpath_user_data);
 
556
                                                }
 
557
                                                else if (seq->type == SEQ_TYPE_IMAGE) {
 
558
                                                        /* might want an option not to loop over all strips */
 
559
                                                        StripElem *se = seq->strip->stripdata;
 
560
                                                        int len = MEM_allocN_len(se) / sizeof(*se);
 
561
                                                        int i;
 
562
 
 
563
                                                        if (flag & BKE_BPATH_TRAVERSE_SKIP_MULTIFILE) {
 
564
                                                                /* only operate on one path */
 
565
                                                                len = MIN2(1, len);
 
566
                                                        }
 
567
 
 
568
                                                        for (i = 0; i < len; i++, se++) {
 
569
                                                                rewrite_path_fixed_dirfile(seq->strip->dir, se->name,
 
570
                                                                                           visit_cb, absbase, bpath_user_data);
 
571
                                                        }
 
572
                                                }
 
573
                                                else {
 
574
                                                        /* simple case */
 
575
                                                        rewrite_path_fixed(seq->strip->dir, visit_cb, absbase, bpath_user_data);
 
576
                                                }
 
577
                                        }
 
578
 
 
579
                                }
 
580
                                SEQ_END
 
581
                        }
 
582
                        break;
 
583
                }
 
584
                case ID_ME:
 
585
                {
 
586
                        Mesh *me = (Mesh *)id;
 
587
                        if (me->ldata.external) {
 
588
                                rewrite_path_fixed(me->ldata.external->filename, visit_cb, absbase, bpath_user_data);
 
589
                        }
 
590
                        break;
 
591
                }
 
592
                case ID_LI:
 
593
                {
 
594
                        Library *lib = (Library *)id;
 
595
                        /* keep packedfile paths always relative to the blend */
 
596
                        if (lib->packedfile == NULL) {
 
597
                                if (rewrite_path_fixed(lib->name, visit_cb, absbase, bpath_user_data)) {
 
598
                                        BKE_library_filepath_set(lib, lib->name);
 
599
                                }
 
600
                        }
 
601
                        break;
 
602
                }
 
603
                case ID_MC:
 
604
                {
 
605
                        MovieClip *clip = (MovieClip *)id;
 
606
                        rewrite_path_fixed(clip->name, visit_cb, absbase, bpath_user_data);
 
607
                        break;
 
608
                }
 
609
                default:
 
610
                        /* Nothing to do for other IDs that don't contain file paths. */
 
611
                        break;
 
612
        }
 
613
}
 
614
 
 
615
void BKE_bpath_traverse_id_list(Main *bmain, ListBase *lb, BPathVisitor visit_cb, const int flag, void *bpath_user_data)
 
616
{
 
617
        ID *id;
 
618
        for (id = lb->first; id; id = id->next) {
 
619
                BKE_bpath_traverse_id(bmain, id, visit_cb, flag, bpath_user_data);
 
620
        }
 
621
}
 
622
 
 
623
void BKE_bpath_traverse_main(Main *bmain, BPathVisitor visit_cb, const int flag, void *bpath_user_data)
 
624
{
 
625
        ListBase *lbarray[MAX_LIBARRAY];
 
626
        int a = set_listbasepointers(bmain, lbarray);
 
627
        while (a--) {
 
628
                BKE_bpath_traverse_id_list(bmain, lbarray[a], visit_cb, flag, bpath_user_data);
 
629
        }
 
630
}
 
631
 
 
632
/* Rewrites a relative path to be relative to the main file - unless the path is
 
633
 * absolute, in which case it is not altered. */
 
634
int BKE_bpath_relocate_visitor(void *pathbase_v, char *path_dst, const char *path_src)
 
635
{
 
636
        /* be sure there is low chance of the path being too short */
 
637
        char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE];
 
638
        const char *base_new = ((char **)pathbase_v)[0];
 
639
        const char *base_old = ((char **)pathbase_v)[1];
 
640
 
 
641
        if (BLI_path_is_rel(base_old)) {
 
642
                printf("%s: error, old base path '%s' is not absolute.\n",
 
643
                       __func__, base_old);
 
644
                return FALSE;
 
645
        }
 
646
 
 
647
        /* Make referenced file absolute. This would be a side-effect of
 
648
         * BLI_cleanup_file, but we do it explicitly so we know if it changed. */
 
649
        BLI_strncpy(filepath, path_src, FILE_MAX);
 
650
        if (BLI_path_abs(filepath, base_old)) {
 
651
                /* Path was relative and is now absolute. Remap.
 
652
                 * Important BLI_cleanup_dir runs before the path is made relative
 
653
                 * because it wont work for paths that start with "//../" */
 
654
                BLI_cleanup_file(base_new, filepath);
 
655
                BLI_path_rel(filepath, base_new);
 
656
                BLI_strncpy(path_dst, filepath, FILE_MAX);
 
657
                return TRUE;
 
658
        }
 
659
        else {
 
660
                /* Path was not relative to begin with. */
 
661
                return FALSE;
 
662
        }
 
663
}
 
664
 
 
665
 
 
666
/* -------------------------------------------------------------------- */
 
667
/**
 
668
 * Backup/Restore/Free functions,
 
669
 * \note These functions assume the data won't chane order.
 
670
 */
 
671
 
 
672
struct PathStore {
 
673
        struct PathStore *next, *prev;
 
674
} PathStore;
 
675
 
 
676
static int bpath_list_append(void *userdata, char *UNUSED(path_dst), const char *path_src)
 
677
{
 
678
        /* store the path and string in a single alloc */
 
679
        ListBase *ls = userdata;
 
680
        size_t path_size = strlen(path_src) + 1;
 
681
        struct PathStore *path_store = MEM_mallocN(sizeof(PathStore) + path_size, __func__);
 
682
        char *filepath = (char *)(path_store + 1);
 
683
 
 
684
        memcpy(filepath, path_src, path_size);
 
685
        BLI_addtail(ls, path_store);
 
686
        return FALSE;
 
687
}
 
688
 
 
689
static int bpath_list_restore(void *userdata, char *path_dst, const char *path_src)
 
690
{
 
691
        /* assume ls->first wont be NULL because the number of paths can't change!
 
692
         * (if they do caller is wrong) */
 
693
        ListBase *ls = userdata;
 
694
        struct PathStore *path_store = ls->first;
 
695
        const char *filepath = (char *)(path_store + 1);
 
696
        int ret;
 
697
 
 
698
        if (strcmp(path_src, filepath) == 0) {
 
699
                ret = FALSE;
 
700
        }
 
701
        else {
 
702
                BLI_strncpy(path_dst, filepath, FILE_MAX);
 
703
                ret = TRUE;
 
704
        }
 
705
 
 
706
        BLI_freelinkN(ls, path_store);
 
707
        return ret;
 
708
}
 
709
 
 
710
/* return ls_handle */
 
711
void *BKE_bpath_list_backup(Main *bmain, const int flag)
 
712
{
 
713
        ListBase *ls = MEM_callocN(sizeof(ListBase), __func__);
 
714
 
 
715
        BKE_bpath_traverse_main(bmain, bpath_list_append, flag, ls);
 
716
 
 
717
        return ls;
 
718
}
 
719
 
 
720
void BKE_bpath_list_restore(Main *bmain, const int flag, void *ls_handle)
 
721
{
 
722
        ListBase *ls = ls_handle;
 
723
 
 
724
        BKE_bpath_traverse_main(bmain, bpath_list_restore, flag, ls);
 
725
}
 
726
 
 
727
void BKE_bpath_list_free(void *ls_handle)
 
728
{
 
729
        ListBase *ls = ls_handle;
 
730
        BLI_assert(ls->first == NULL);  /* assumes we were used */
 
731
        BLI_freelistN(ls);
 
732
        MEM_freeN(ls);
 
733
}