Blender V2.61 - r43446
|
00001 /* 00002 * ***** BEGIN GPL LICENSE BLOCK ***** 00003 * 00004 * This program is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software Foundation, 00016 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 00017 * 00018 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. 00019 * All rights reserved. 00020 * 00021 * The Original Code is: all of this file. 00022 * 00023 * Contributor(s): Campbell barton, Alex Fraser 00024 * 00025 * ***** END GPL LICENSE BLOCK ***** 00026 */ 00027 00032 /* TODO, 00033 * currently there are some cases we dont support. 00034 * - passing output paths to the visitor?, like render out. 00035 * - passing sequence strips with many images. 00036 * - passing directory paths - visitors dont know which path is a dir or a file. 00037 * */ 00038 00039 #include <sys/stat.h> 00040 00041 #include <string.h> 00042 #include <assert.h> 00043 00044 /* path/file handeling stuff */ 00045 #ifndef WIN32 00046 #include <dirent.h> 00047 #include <unistd.h> 00048 #else 00049 #include <io.h> 00050 #include "BLI_winstuff.h" 00051 #endif 00052 00053 #include "MEM_guardedalloc.h" 00054 00055 #include "DNA_brush_types.h" 00056 #include "DNA_image_types.h" 00057 #include "DNA_mesh_types.h" 00058 #include "DNA_modifier_types.h" 00059 #include "DNA_movieclip_types.h" 00060 #include "DNA_object_fluidsim.h" 00061 #include "DNA_object_force.h" 00062 #include "DNA_object_types.h" 00063 #include "DNA_particle_types.h" 00064 #include "DNA_sequence_types.h" 00065 #include "DNA_sound_types.h" 00066 #include "DNA_text_types.h" 00067 #include "DNA_texture_types.h" 00068 #include "DNA_vfont_types.h" 00069 #include "DNA_scene_types.h" 00070 #include "DNA_smoke_types.h" 00071 00072 #include "BLI_blenlib.h" 00073 #include "BLI_bpath.h" 00074 #include "BLI_utildefines.h" 00075 00076 #include "BKE_library.h" 00077 #include "BKE_main.h" 00078 #include "BKE_report.h" 00079 #include "BKE_sequencer.h" 00080 #include "BKE_utildefines.h" 00081 #include "BKE_image.h" /* so we can check the image's type */ 00082 00083 static int checkMissingFiles_visit_cb(void *userdata, char *UNUSED(path_dst), const char *path_src) 00084 { 00085 ReportList *reports= (ReportList *)userdata; 00086 00087 if (!BLI_exists(path_src)) { 00088 BKE_reportf(reports, RPT_WARNING, "Path Not Found \"%s\"", path_src); 00089 } 00090 00091 return FALSE; 00092 } 00093 00094 /* high level function */ 00095 void checkMissingFiles(Main *bmain, ReportList *reports) 00096 { 00097 bpath_traverse_main(bmain, checkMissingFiles_visit_cb, BPATH_TRAVERSE_ABS, reports); 00098 } 00099 00100 typedef struct BPathRemap_Data 00101 { 00102 const char *basedir; 00103 ReportList *reports; 00104 00105 int count_tot; 00106 int count_changed; 00107 int count_failed; 00108 } BPathRemap_Data; 00109 00110 static int makeFilesRelative_visit_cb(void *userdata, char *path_dst, const char *path_src) 00111 { 00112 BPathRemap_Data *data= (BPathRemap_Data *)userdata; 00113 00114 data->count_tot++; 00115 00116 if(strncmp(path_src, "//", 2)==0) { 00117 return FALSE; /* already relative */ 00118 } 00119 else { 00120 strcpy(path_dst, path_src); 00121 BLI_path_rel(path_dst, data->basedir); 00122 if (strncmp(path_dst, "//", 2)==0) { 00123 data->count_changed++; 00124 } 00125 else { 00126 BKE_reportf(data->reports, RPT_WARNING, "Path cant be made relative \"%s\"", path_src); 00127 data->count_failed++; 00128 } 00129 return TRUE; 00130 } 00131 } 00132 00133 void makeFilesRelative(Main *bmain, const char *basedir, ReportList *reports) 00134 { 00135 BPathRemap_Data data= {NULL}; 00136 00137 if(basedir[0] == '\0') { 00138 printf("%s: basedir='', this is a bug\n", __func__); 00139 return; 00140 } 00141 00142 data.basedir= basedir; 00143 data.reports= reports; 00144 00145 bpath_traverse_main(bmain, makeFilesRelative_visit_cb, 0, (void *)&data); 00146 00147 BKE_reportf(reports, data.count_failed ? RPT_WARNING : RPT_INFO, 00148 "Total files %d|Changed %d|Failed %d", 00149 data.count_tot, data.count_changed, data.count_failed); 00150 } 00151 00152 static int makeFilesAbsolute_visit_cb(void *userdata, char *path_dst, const char *path_src) 00153 { 00154 BPathRemap_Data *data= (BPathRemap_Data *)userdata; 00155 00156 data->count_tot++; 00157 00158 if(strncmp(path_src, "//", 2)!=0) { 00159 return FALSE; /* already absolute */ 00160 } 00161 else { 00162 strcpy(path_dst, path_src); 00163 BLI_path_abs(path_dst, data->basedir); 00164 if (strncmp(path_dst, "//", 2)!=0) { 00165 data->count_changed++; 00166 } 00167 else { 00168 BKE_reportf(data->reports, RPT_WARNING, "Path cant be made absolute \"%s\"", path_src); 00169 data->count_failed++; 00170 } 00171 return TRUE; 00172 } 00173 } 00174 00175 /* similar to makeFilesRelative - keep in sync! */ 00176 void makeFilesAbsolute(Main *bmain, const char *basedir, ReportList *reports) 00177 { 00178 BPathRemap_Data data= {NULL}; 00179 00180 if(basedir[0] == '\0') { 00181 printf("%s: basedir='', this is a bug\n", __func__); 00182 return; 00183 } 00184 00185 data.basedir= basedir; 00186 data.reports= reports; 00187 00188 bpath_traverse_main(bmain, makeFilesAbsolute_visit_cb, 0, (void *)&data); 00189 00190 BKE_reportf(reports, data.count_failed ? RPT_WARNING : RPT_INFO, 00191 "Total files %d|Changed %d|Failed %d", 00192 data.count_tot, data.count_changed, data.count_failed); 00193 } 00194 00195 00196 /* find this file recursively, use the biggest file so thumbnails dont get used by mistake 00197 - dir: subdir to search 00198 - filename: set this filename 00199 - filesize: filesize for the file 00200 */ 00201 #define MAX_RECUR 16 00202 static int findFileRecursive(char *filename_new, 00203 const char *dirname, 00204 const char *filename, 00205 int *filesize, 00206 int *recur_depth) 00207 { 00208 /* file searching stuff */ 00209 DIR *dir; 00210 struct dirent *de; 00211 struct stat status; 00212 char path[FILE_MAX]; 00213 int size; 00214 00215 dir= opendir(dirname); 00216 00217 if (dir==NULL) 00218 return 0; 00219 00220 if (*filesize == -1) 00221 *filesize= 0; /* dir opened fine */ 00222 00223 while ((de= readdir(dir)) != NULL) { 00224 00225 if (strcmp(".", de->d_name)==0 || strcmp("..", de->d_name)==0) 00226 continue; 00227 00228 BLI_join_dirfile(path, sizeof(path), dirname, de->d_name); 00229 00230 if (stat(path, &status) != 0) 00231 continue; /* cant stat, dont bother with this file, could print debug info here */ 00232 00233 if (S_ISREG(status.st_mode)) { /* is file */ 00234 if (strncmp(filename, de->d_name, FILE_MAX)==0) { /* name matches */ 00235 /* open the file to read its size */ 00236 size= status.st_size; 00237 if ((size > 0) && (size > *filesize)) { /* find the biggest file */ 00238 *filesize= size; 00239 BLI_strncpy(filename_new, path, FILE_MAX); 00240 } 00241 } 00242 } 00243 else if (S_ISDIR(status.st_mode)) { /* is subdir */ 00244 if (*recur_depth <= MAX_RECUR) { 00245 (*recur_depth)++; 00246 findFileRecursive(filename_new, path, filename, filesize, recur_depth); 00247 (*recur_depth)--; 00248 } 00249 } 00250 } 00251 closedir(dir); 00252 return 1; 00253 } 00254 00255 typedef struct BPathFind_Data 00256 { 00257 const char *basedir; 00258 char searchdir[FILE_MAX]; 00259 ReportList *reports; 00260 } BPathFind_Data; 00261 00262 static int findMissingFiles_visit_cb(void *userdata, char *path_dst, const char *path_src) 00263 { 00264 BPathFind_Data *data= (BPathFind_Data *)userdata; 00265 char filename_new[FILE_MAX]; 00266 00267 int filesize= -1; 00268 int recur_depth= 0; 00269 00270 findFileRecursive(filename_new, 00271 data->searchdir, BLI_path_basename((char *)path_src), 00272 &filesize, &recur_depth); 00273 00274 if (filesize == -1) { /* could not open dir */ 00275 BKE_reportf(data->reports, RPT_WARNING, 00276 "Could not find \"%s\" in \"%s\"", 00277 BLI_path_basename((char *)path_src), data->searchdir); 00278 return FALSE; 00279 } 00280 else { 00281 strcpy(path_dst, filename_new); 00282 return TRUE; 00283 } 00284 } 00285 00286 void findMissingFiles(Main *bmain, const char *searchpath, ReportList *reports) 00287 { 00288 struct BPathFind_Data data= {NULL}; 00289 00290 data.reports= reports; 00291 BLI_split_dir_part(searchpath, data.searchdir, sizeof(data.searchdir)); 00292 00293 bpath_traverse_main(bmain, findMissingFiles_visit_cb, 0, (void *)&data); 00294 } 00295 00296 /* Run a visitor on a string, replacing the contents of the string as needed. */ 00297 static int rewrite_path_fixed(char *path, BPathVisitor visit_cb, const char *absbase, void *userdata) 00298 { 00299 char path_src_buf[FILE_MAX]; 00300 const char *path_src; 00301 char path_dst[FILE_MAX]; 00302 00303 if (absbase) { 00304 BLI_strncpy(path_src_buf, path, sizeof(path_src_buf)); 00305 BLI_path_abs(path_src_buf, absbase); 00306 path_src= path_src_buf; 00307 } 00308 else { 00309 path_src= path; 00310 } 00311 00312 if (visit_cb(userdata, path_dst, path_src)) { 00313 BLI_strncpy(path, path_dst, FILE_MAX); 00314 return TRUE; 00315 } 00316 else { 00317 return FALSE; 00318 } 00319 } 00320 00321 static int rewrite_path_fixed_dirfile(char path_dir[FILE_MAXDIR], 00322 char path_file[FILE_MAXFILE], 00323 BPathVisitor visit_cb, 00324 const char *absbase, 00325 void *userdata) 00326 { 00327 char path_src[FILE_MAX]; 00328 char path_dst[FILE_MAX]; 00329 00330 BLI_join_dirfile(path_src, sizeof(path_src), path_dir, path_file); 00331 00332 if (absbase) { 00333 BLI_path_abs(path_src, absbase); 00334 } 00335 00336 if (visit_cb(userdata, path_dst, (const char *)path_src)) { 00337 BLI_split_dirfile(path_dst, path_dir, path_file, FILE_MAXDIR, FILE_MAXFILE); 00338 return TRUE; 00339 } 00340 else { 00341 return FALSE; 00342 } 00343 } 00344 00345 static int rewrite_path_alloc(char **path, BPathVisitor visit_cb, const char *absbase, void *userdata) 00346 { 00347 char path_src_buf[FILE_MAX]; 00348 const char *path_src; 00349 char path_dst[FILE_MAX]; 00350 00351 if (absbase) { 00352 BLI_strncpy(path_src_buf, *path, sizeof(path_src_buf)); 00353 BLI_path_abs(path_src_buf, absbase); 00354 path_src= path_src_buf; 00355 } 00356 else { 00357 path_src= *path; 00358 } 00359 00360 if (visit_cb(userdata, path_dst, path_src)) { 00361 MEM_freeN((*path)); 00362 (*path)= BLI_strdup(path_dst); 00363 return TRUE; 00364 } 00365 else { 00366 return FALSE; 00367 } 00368 } 00369 00370 /* Run visitor function 'visit' on all paths contained in 'id'. */ 00371 void bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int flag, void *bpath_user_data) 00372 { 00373 Image *ima; 00374 const char *absbase= (flag & BPATH_TRAVERSE_ABS) ? ID_BLEND_PATH(bmain, id) : NULL; 00375 00376 if ((flag & BPATH_TRAVERSE_SKIP_LIBRARY) && id->lib) { 00377 return; 00378 } 00379 00380 switch(GS(id->name)) { 00381 case ID_IM: 00382 ima= (Image *)id; 00383 if (ima->packedfile == NULL || (flag & BPATH_TRAVERSE_SKIP_PACKED) == 0) { 00384 if (ELEM3(ima->source, IMA_SRC_FILE, IMA_SRC_MOVIE, IMA_SRC_SEQUENCE)) { 00385 rewrite_path_fixed(ima->name, visit_cb, absbase, bpath_user_data); 00386 } 00387 } 00388 break; 00389 case ID_BR: 00390 { 00391 Brush *brush= (Brush *)id; 00392 if (brush->icon_filepath[0]) { 00393 rewrite_path_fixed(brush->icon_filepath, visit_cb, absbase, bpath_user_data); 00394 } 00395 } 00396 break; 00397 case ID_OB: 00398 00399 #define BPATH_TRAVERSE_POINTCACHE(ptcaches) \ 00400 { \ 00401 PointCache *cache; \ 00402 for(cache= (ptcaches).first; cache; cache= cache->next) { \ 00403 if(cache->flag & PTCACHE_DISK_CACHE) { \ 00404 rewrite_path_fixed(cache->path, \ 00405 visit_cb, \ 00406 absbase, \ 00407 bpath_user_data); \ 00408 } \ 00409 } \ 00410 } \ 00411 00412 00413 { 00414 Object *ob= (Object *)id; 00415 ModifierData *md; 00416 ParticleSystem *psys; 00417 00418 00419 /* do via modifiers instead */ 00420 #if 0 00421 if (ob->fluidsimSettings) { 00422 rewrite_path_fixed(ob->fluidsimSettings->surfdataPath, visit_cb, absbase, bpath_user_data); 00423 } 00424 #endif 00425 00426 for (md= ob->modifiers.first; md; md= md->next) { 00427 if (md->type == eModifierType_Fluidsim) { 00428 FluidsimModifierData *fluidmd= (FluidsimModifierData *)md; 00429 if (fluidmd->fss) { 00430 rewrite_path_fixed(fluidmd->fss->surfdataPath, visit_cb, absbase, bpath_user_data); 00431 } 00432 } 00433 else if (md->type == eModifierType_Smoke) { 00434 SmokeModifierData *smd= (SmokeModifierData *)md; 00435 if(smd->type & MOD_SMOKE_TYPE_DOMAIN) { 00436 BPATH_TRAVERSE_POINTCACHE(smd->domain->ptcaches[0]); 00437 } 00438 } 00439 else if (md->type==eModifierType_Cloth) { 00440 ClothModifierData *clmd= (ClothModifierData*) md; 00441 BPATH_TRAVERSE_POINTCACHE(clmd->ptcaches); 00442 } 00443 else if (md->type==eModifierType_Ocean) { 00444 OceanModifierData *omd= (OceanModifierData*) md; 00445 rewrite_path_fixed(omd->cachepath, visit_cb, absbase, bpath_user_data); 00446 } 00447 } 00448 00449 if (ob->soft) { 00450 BPATH_TRAVERSE_POINTCACHE(ob->soft->ptcaches); 00451 } 00452 00453 for (psys= ob->particlesystem.first; psys; psys= psys->next) { 00454 BPATH_TRAVERSE_POINTCACHE(psys->ptcaches); 00455 } 00456 } 00457 00458 #undef BPATH_TRAVERSE_POINTCACHE 00459 00460 break; 00461 case ID_SO: 00462 { 00463 bSound *sound= (bSound *)id; 00464 if (sound->packedfile == NULL || (flag & BPATH_TRAVERSE_SKIP_PACKED) == 0) { 00465 rewrite_path_fixed(sound->name, visit_cb, absbase, bpath_user_data); 00466 } 00467 } 00468 break; 00469 case ID_TXT: 00470 if (((Text*)id)->name) { 00471 rewrite_path_alloc(&((Text *)id)->name, visit_cb, absbase, bpath_user_data); 00472 } 00473 break; 00474 case ID_VF: 00475 { 00476 VFont *vf= (VFont *)id; 00477 if (vf->packedfile == NULL || (flag & BPATH_TRAVERSE_SKIP_PACKED) == 0) { 00478 if (strcmp(vf->name, FO_BUILTIN_NAME) != 0) { 00479 rewrite_path_fixed(((VFont *)id)->name, visit_cb, absbase, bpath_user_data); 00480 } 00481 } 00482 } 00483 break; 00484 case ID_TE: 00485 { 00486 Tex *tex = (Tex *)id; 00487 if (tex->plugin) { 00488 /* FIXME: rewrite_path assumes path length of FILE_MAX, but 00489 tex->plugin->name is 160. ... is this field even a path? */ 00490 //rewrite_path(tex->plugin->name, visit_cb, bpath_user_data); 00491 } 00492 if (tex->type == TEX_VOXELDATA && TEX_VD_IS_SOURCE_PATH(tex->vd->file_format)) { 00493 rewrite_path_fixed(tex->vd->source_path, visit_cb, absbase, bpath_user_data); 00494 } 00495 } 00496 break; 00497 00498 case ID_SCE: 00499 { 00500 Scene *scene= (Scene *)id; 00501 if (scene->ed) { 00502 Sequence *seq; 00503 00504 SEQ_BEGIN(scene->ed, seq) { 00505 if (SEQ_HAS_PATH(seq)) { 00506 if (ELEM(seq->type, SEQ_MOVIE, SEQ_SOUND)) { 00507 rewrite_path_fixed_dirfile(seq->strip->dir, seq->strip->stripdata->name, 00508 visit_cb, absbase, bpath_user_data); 00509 } 00510 else if (seq->type == SEQ_IMAGE) { 00511 /* might want an option not to loop over all strips */ 00512 StripElem *se= seq->strip->stripdata; 00513 int len= MEM_allocN_len(se) / sizeof(*se); 00514 int i; 00515 00516 if (flag & BPATH_TRAVERSE_SKIP_MULTIFILE) { 00517 /* only operate on one path */ 00518 len= MIN2(1, len); 00519 } 00520 00521 for(i= 0; i < len; i++, se++) { 00522 rewrite_path_fixed_dirfile(seq->strip->dir, se->name, 00523 visit_cb, absbase, bpath_user_data); 00524 } 00525 } 00526 else { 00527 /* simple case */ 00528 rewrite_path_fixed(seq->strip->dir, visit_cb, absbase, bpath_user_data); 00529 } 00530 } 00531 else if (seq->plugin) { 00532 rewrite_path_fixed(seq->plugin->name, visit_cb, absbase, bpath_user_data); 00533 } 00534 00535 } 00536 SEQ_END 00537 } 00538 } 00539 break; 00540 case ID_ME: 00541 { 00542 Mesh *me= (Mesh *)id; 00543 if (me->fdata.external) { 00544 rewrite_path_fixed(me->fdata.external->filename, visit_cb, absbase, bpath_user_data); 00545 } 00546 } 00547 break; 00548 case ID_LI: 00549 { 00550 Library *lib= (Library *)id; 00551 if(rewrite_path_fixed(lib->name, visit_cb, absbase, bpath_user_data)) { 00552 BKE_library_filepath_set(lib, lib->name); 00553 } 00554 } 00555 break; 00556 case ID_MC: 00557 { 00558 MovieClip *clip= (MovieClip *)id; 00559 rewrite_path_fixed(clip->name, visit_cb, absbase, bpath_user_data); 00560 } 00561 break; 00562 default: 00563 /* Nothing to do for other IDs that don't contain file paths. */ 00564 break; 00565 } 00566 } 00567 00568 void bpath_traverse_id_list(Main *bmain, ListBase *lb, BPathVisitor visit_cb, const int flag, void *bpath_user_data) 00569 { 00570 ID *id; 00571 for(id= lb->first; id; id= id->next) { 00572 bpath_traverse_id(bmain, id, visit_cb, flag, bpath_user_data); 00573 } 00574 } 00575 00576 void bpath_traverse_main(Main *bmain, BPathVisitor visit_cb, const int flag, void *bpath_user_data) 00577 { 00578 ListBase *lbarray[MAX_LIBARRAY]; 00579 int a= set_listbasepointers(bmain, lbarray); 00580 while(a--) bpath_traverse_id_list(bmain, lbarray[a], visit_cb, flag, bpath_user_data); 00581 } 00582 00583 /* Rewrites a relative path to be relative to the main file - unless the path is 00584 absolute, in which case it is not altered. */ 00585 int bpath_relocate_visitor(void *pathbase_v, char *path_dst, const char *path_src) 00586 { 00587 /* be sure there is low chance of the path being too short */ 00588 char filepath[(FILE_MAXDIR * 2) + FILE_MAXFILE]; 00589 const char *base_new= ((char **)pathbase_v)[0]; 00590 const char *base_old= ((char **)pathbase_v)[1]; 00591 00592 if (strncmp(base_old, "//", 2) == 0) { 00593 printf("%s: error, old base path '%s' is not absolute.\n", 00594 __func__, base_old); 00595 return FALSE; 00596 } 00597 00598 /* Make referenced file absolute. This would be a side-effect of 00599 BLI_cleanup_file, but we do it explicitely so we know if it changed. */ 00600 BLI_strncpy(filepath, path_src, FILE_MAX); 00601 if (BLI_path_abs(filepath, base_old)) { 00602 /* Path was relative and is now absolute. Remap. 00603 * Important BLI_cleanup_dir runs before the path is made relative 00604 * because it wont work for paths that start with "//../" */ 00605 BLI_cleanup_file(base_new, filepath); 00606 BLI_path_rel(filepath, base_new); 00607 BLI_strncpy(path_dst, filepath, FILE_MAX); 00608 return TRUE; 00609 } 00610 else { 00611 /* Path was not relative to begin with. */ 00612 return FALSE; 00613 } 00614 }