2011-02-23 10:52:22 +00:00
|
|
|
/*
|
2008-01-07 19:13:47 +00:00
|
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
2002-10-12 11:37:38 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
2008-01-07 19:13:47 +00:00
|
|
|
* of the License, or (at your option) any later version.
|
2002-10-12 11:37:38 +00:00
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software Foundation,
|
2010-02-12 13:34:04 +00:00
|
|
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
2002-10-12 11:37:38 +00:00
|
|
|
*
|
|
|
|
* The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* The Original Code is: all of this file.
|
|
|
|
*
|
|
|
|
* Contributor(s): none yet.
|
|
|
|
*
|
2008-01-07 19:13:47 +00:00
|
|
|
* ***** END GPL LICENSE BLOCK *****
|
2009-12-13 15:48:57 +00:00
|
|
|
*
|
|
|
|
* various string, file, list operations.
|
2002-10-12 11:37:38 +00:00
|
|
|
*/
|
|
|
|
|
2011-02-27 20:37:56 +00:00
|
|
|
/** \file blender/blenlib/intern/path_util.c
|
|
|
|
* \ingroup bli
|
|
|
|
*/
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
#include <ctype.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdlib.h>
|
2010-11-07 08:49:07 +00:00
|
|
|
#include <assert.h>
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2011-10-21 17:37:38 +00:00
|
|
|
#include "DNA_listBase.h"
|
2008-02-13 13:55:22 +00:00
|
|
|
|
2013-03-04 18:36:37 +00:00
|
|
|
#include "BLI_utildefines.h"
|
2009-12-13 17:46:30 +00:00
|
|
|
#include "BLI_fileops.h"
|
|
|
|
#include "BLI_path_util.h"
|
|
|
|
#include "BLI_string.h"
|
2011-11-21 11:53:29 +00:00
|
|
|
#include "BLI_string_utf8.h"
|
2013-08-27 18:29:30 +00:00
|
|
|
#include "BLI_fnmatch.h"
|
2002-10-12 11:37:38 +00:00
|
|
|
|
T39690: Modifications to Blender's 'temp dir' system.
Current temporary data of Blender suffers one major issue - default 'temp' dir on Windows is never
automatically cleaned up, and can end being quite big when used by Blender, especially when we have
to store per-process data (using getpid() in file names).
To address this, this patch:
* Divides tempdir paths in two, one for 'base' temp dir (the same as previous unique tempdir path),
the other is a mkdtemp-generated sub-dir, specific to each Blender instance.
* Only uses base tempdir when we need some shallow persistance accross Blender sessions - and we always
reuse the same filename (quit.blend...) or generate small file (crash reports...).
* Uses temp sub-dir for heavy files like pointcache or renderEXRs (Save Buffer option).
* Erases temp sub-dir on quit or crash.
To get this working it also adds a working 'recursive delete' to BLI_delete() under Windows.
Note that, as in current code, the 'recover render result' hack-feature that was possible
with SaveBuffer option is still removed. A real renderresult cache feature will be added
soon, though.
Reviewers: campbellbarton, brecht, sergey
Reviewed By: campbellbarton, sergey
CC: sergey
Differential Revision: https://developer.blender.org/D531
2014-06-23 13:42:19 +02:00
|
|
|
#ifdef WIN32
|
2013-03-29 00:50:52 +00:00
|
|
|
# include "utf_winfunc.h"
|
|
|
|
# include "utfconv.h"
|
2011-11-02 22:00:22 +00:00
|
|
|
# include <io.h>
|
|
|
|
# ifdef _WIN32_IE
|
|
|
|
# undef _WIN32_IE
|
|
|
|
# endif
|
|
|
|
# define _WIN32_IE 0x0501
|
|
|
|
# include <windows.h>
|
|
|
|
# include <shlobj.h>
|
|
|
|
# include "BLI_winstuff.h"
|
2015-06-04 16:48:56 +10:00
|
|
|
# include "BLI_alloca.h"
|
2015-04-08 21:57:49 +02:00
|
|
|
#else
|
|
|
|
# include "unistd.h"
|
2010-03-20 18:52:03 +00:00
|
|
|
#endif /* WIN32 */
|
|
|
|
|
2015-07-14 18:42:22 +02:00
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
|
|
|
|
/* Declarations */
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
|
|
|
|
/* return true if the path is absolute ie starts with a drive specifier (eg A:\) or is a UNC path */
|
|
|
|
static bool BLI_path_is_abs(const char *name);
|
|
|
|
|
|
|
|
#endif /* WIN32 */
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
/* implementation */
|
|
|
|
|
2013-03-04 19:27:51 +00:00
|
|
|
/**
|
|
|
|
* Looks for a sequence of decimal digits in string, preceding any filename extension,
|
|
|
|
* returning the integer value if found, or 0 if not.
|
|
|
|
*
|
|
|
|
* \param string String to scan.
|
|
|
|
* \param head Optional area to return copy of part of string prior to digits, or before dot if no digits.
|
|
|
|
* \param tail Optional area to return copy of part of string following digits, or from dot if no digits.
|
|
|
|
* \param numlen Optional to return number of digits found.
|
|
|
|
*/
|
2010-04-23 23:01:50 +00:00
|
|
|
int BLI_stringdec(const char *string, char *head, char *tail, unsigned short *numlen)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2017-10-28 17:48:45 +11:00
|
|
|
uint nums = 0, nume = 0;
|
2013-11-24 16:20:04 +11:00
|
|
|
int i;
|
2013-03-04 19:27:51 +00:00
|
|
|
bool found_digit = false;
|
|
|
|
const char * const lslash = BLI_last_slash(string);
|
2017-10-28 17:48:45 +11:00
|
|
|
const uint string_len = strlen(string);
|
|
|
|
const uint lslash_len = lslash != NULL ? (int)(lslash - string) : 0;
|
|
|
|
uint name_end = string_len;
|
2013-03-04 19:27:51 +00:00
|
|
|
|
|
|
|
while (name_end > lslash_len && string[--name_end] != '.') {} /* name ends at dot if present */
|
|
|
|
if (name_end == lslash_len && string[name_end] != '.') name_end = string_len;
|
|
|
|
|
2013-11-25 21:13:58 +11:00
|
|
|
for (i = name_end - 1; i >= (int)lslash_len; i--) {
|
2002-10-12 11:37:38 +00:00
|
|
|
if (isdigit(string[i])) {
|
2013-03-04 19:27:51 +00:00
|
|
|
if (found_digit) {
|
2002-10-12 11:37:38 +00:00
|
|
|
nums = i;
|
|
|
|
}
|
2012-03-24 06:18:31 +00:00
|
|
|
else {
|
2002-10-12 11:37:38 +00:00
|
|
|
nume = i;
|
|
|
|
nums = i;
|
2013-03-04 19:27:51 +00:00
|
|
|
found_digit = true;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
}
|
2007-10-04 10:50:15 +00:00
|
|
|
else {
|
2013-03-04 19:27:51 +00:00
|
|
|
if (found_digit) break;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
}
|
2013-03-24 01:51:54 +00:00
|
|
|
|
2013-03-04 19:27:51 +00:00
|
|
|
if (found_digit) {
|
2012-05-12 15:13:06 +00:00
|
|
|
if (tail) strcpy(tail, &string[nume + 1]);
|
2010-07-04 17:14:06 +00:00
|
|
|
if (head) {
|
2012-04-29 15:47:02 +00:00
|
|
|
strcpy(head, string);
|
2012-05-12 15:13:06 +00:00
|
|
|
head[nums] = 0;
|
2010-07-04 17:14:06 +00:00
|
|
|
}
|
2012-05-12 15:13:06 +00:00
|
|
|
if (numlen) *numlen = nume - nums + 1;
|
2002-10-12 11:37:38 +00:00
|
|
|
return ((int)atoi(&(string[nums])));
|
|
|
|
}
|
2013-03-24 01:51:54 +00:00
|
|
|
else {
|
|
|
|
if (tail) strcpy(tail, string + name_end);
|
|
|
|
if (head) {
|
2013-03-26 15:52:43 +00:00
|
|
|
/* name_end points to last character of head,
|
|
|
|
* make it +1 so null-terminator is nicely placed
|
|
|
|
*/
|
|
|
|
BLI_strncpy(head, string, name_end + 1);
|
2013-03-24 01:51:54 +00:00
|
|
|
}
|
|
|
|
if (numlen) *numlen = 0;
|
|
|
|
return 0;
|
2010-07-04 17:14:06 +00:00
|
|
|
}
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-04 19:27:51 +00:00
|
|
|
/**
|
|
|
|
* Returns in area pointed to by string a string of the form "<head><pic><tail>", where pic
|
|
|
|
* is formatted as numlen digits with leading zeroes.
|
|
|
|
*/
|
2010-04-23 23:01:50 +00:00
|
|
|
void BLI_stringenc(char *string, const char *head, const char *tail, unsigned short numlen, int pic)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2013-03-10 11:02:21 +00:00
|
|
|
sprintf(string, "%s%.*d%s", head, numlen, MAX2(0, pic), tail);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
2014-04-21 16:49:35 +02:00
|
|
|
static int BLI_path_unc_prefix_len(const char *path); /* defined below in same file */
|
2010-11-07 08:49:07 +00:00
|
|
|
|
2005-12-14 13:21:32 +00:00
|
|
|
/* ******************** string encoding ***************** */
|
|
|
|
|
2015-10-17 16:04:54 +11:00
|
|
|
/**
|
|
|
|
* Remove redundant characters from \a path and optionally make absolute.
|
|
|
|
*
|
2016-06-27 13:20:56 +10:00
|
|
|
* \param relabase: The path this is relative to, or ignored when NULL.
|
2015-10-17 16:04:54 +11:00
|
|
|
* \param path: Can be any input, and this function converts it to a regular full path.
|
|
|
|
* Also removes garbage from directory paths, like `/../` or double slashes etc.
|
|
|
|
*
|
|
|
|
* \note \a path isn't protected for max string names...
|
2005-12-14 13:21:32 +00:00
|
|
|
*/
|
2013-03-05 04:35:14 +00:00
|
|
|
void BLI_cleanup_path(const char *relabase, char *path)
|
2005-12-14 13:21:32 +00:00
|
|
|
{
|
2011-12-21 20:56:49 +00:00
|
|
|
ptrdiff_t a;
|
2005-12-14 13:21:32 +00:00
|
|
|
char *start, *eind;
|
2008-04-28 21:29:15 +00:00
|
|
|
if (relabase) {
|
2013-03-05 04:35:14 +00:00
|
|
|
BLI_path_abs(path, relabase);
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-03-05 04:35:14 +00:00
|
|
|
if (path[0] == '/' && path[1] == '/') {
|
|
|
|
if (path[2] == '\0') {
|
2008-06-05 13:02:00 +00:00
|
|
|
return; /* path is "//" - cant clean it */
|
|
|
|
}
|
2013-03-10 04:43:15 +00:00
|
|
|
path = path + 2; /* leave the initial "//" untouched */
|
2008-06-05 13:02:00 +00:00
|
|
|
}
|
2008-04-28 21:29:15 +00:00
|
|
|
}
|
2005-12-14 13:21:32 +00:00
|
|
|
|
2008-06-11 09:04:41 +00:00
|
|
|
/* Note
|
2012-03-11 19:09:01 +00:00
|
|
|
* memmove(start, eind, strlen(eind) + 1);
|
2008-06-11 09:04:41 +00:00
|
|
|
* is the same as
|
2015-02-07 04:33:48 +11:00
|
|
|
* strcpy(start, eind);
|
2008-06-11 09:04:41 +00:00
|
|
|
* except strcpy should not be used because there is overlap,
|
2012-03-03 20:19:11 +00:00
|
|
|
* so use memmove's slightly more obscure syntax - Campbell
|
2008-06-11 09:04:41 +00:00
|
|
|
*/
|
2005-12-14 13:21:32 +00:00
|
|
|
|
|
|
|
#ifdef WIN32
|
2013-03-05 04:35:14 +00:00
|
|
|
while ( (start = strstr(path, "\\..\\")) ) {
|
2005-12-14 13:21:32 +00:00
|
|
|
eind = start + strlen("\\..\\") - 1;
|
2013-03-05 04:35:14 +00:00
|
|
|
a = start - path - 1;
|
2012-05-12 15:13:06 +00:00
|
|
|
while (a > 0) {
|
2013-03-05 04:35:14 +00:00
|
|
|
if (path[a] == '\\') break;
|
2005-12-14 13:21:32 +00:00
|
|
|
a--;
|
|
|
|
}
|
2012-05-12 15:13:06 +00:00
|
|
|
if (a < 0) {
|
2008-06-14 16:54:46 +00:00
|
|
|
break;
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-03-05 04:35:14 +00:00
|
|
|
memmove(path + a, eind, strlen(eind) + 1);
|
2008-06-14 16:54:46 +00:00
|
|
|
}
|
2005-12-14 13:21:32 +00:00
|
|
|
}
|
|
|
|
|
2013-03-05 04:35:14 +00:00
|
|
|
while ( (start = strstr(path, "\\.\\")) ) {
|
2005-12-14 13:21:32 +00:00
|
|
|
eind = start + strlen("\\.\\") - 1;
|
2012-03-11 19:09:01 +00:00
|
|
|
memmove(start, eind, strlen(eind) + 1);
|
2005-12-14 13:21:32 +00:00
|
|
|
}
|
|
|
|
|
2014-04-21 16:49:35 +02:00
|
|
|
/* remove two consecutive backslashes, but skip the UNC prefix,
|
|
|
|
* which needs to be preserved */
|
|
|
|
while ( (start = strstr(path + BLI_path_unc_prefix_len(path), "\\\\")) ) {
|
2005-12-14 13:21:32 +00:00
|
|
|
eind = start + strlen("\\\\") - 1;
|
2012-03-11 19:09:01 +00:00
|
|
|
memmove(start, eind, strlen(eind) + 1);
|
2005-12-14 13:21:32 +00:00
|
|
|
}
|
2007-12-31 12:03:26 +00:00
|
|
|
#else
|
2013-03-05 04:35:14 +00:00
|
|
|
while ( (start = strstr(path, "/../")) ) {
|
|
|
|
a = start - path - 1;
|
2013-03-10 04:43:15 +00:00
|
|
|
if (a > 0) {
|
|
|
|
/* <prefix>/<parent>/../<postfix> => <prefix>/<postfix> */
|
|
|
|
eind = start + (4 - 1) /* strlen("/../") - 1 */; /* strip "/.." and keep last "/" */
|
|
|
|
while (a > 0 && path[a] != '/') { /* find start of <parent> */
|
|
|
|
a--;
|
|
|
|
}
|
|
|
|
memmove(path + a, eind, strlen(eind) + 1);
|
2012-03-11 19:09:01 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-03-10 04:43:15 +00:00
|
|
|
/* support for odd paths: eg /../home/me --> /home/me
|
|
|
|
* this is a valid path in blender but we cant handle this the usual way below
|
|
|
|
* simply strip this prefix then evaluate the path as usual.
|
|
|
|
* pythons os.path.normpath() does this */
|
|
|
|
|
|
|
|
/* Note: previous version of following call used an offset of 3 instead of 4,
|
|
|
|
* which meant that the "/../home/me" example actually became "home/me".
|
|
|
|
* Using offset of 3 gives behaviour consistent with the abovementioned
|
|
|
|
* Python routine. */
|
|
|
|
memmove(path, path + 3, strlen(path + 3) + 1);
|
2008-06-14 16:54:46 +00:00
|
|
|
}
|
2005-12-14 13:21:32 +00:00
|
|
|
}
|
|
|
|
|
2013-03-05 04:35:14 +00:00
|
|
|
while ( (start = strstr(path, "/./")) ) {
|
2010-09-17 15:11:12 +00:00
|
|
|
eind = start + (3 - 1) /* strlen("/./") - 1 */;
|
2012-03-11 19:09:01 +00:00
|
|
|
memmove(start, eind, strlen(eind) + 1);
|
2005-12-14 13:21:32 +00:00
|
|
|
}
|
|
|
|
|
2013-03-05 04:35:14 +00:00
|
|
|
while ( (start = strstr(path, "//")) ) {
|
2010-09-17 15:11:12 +00:00
|
|
|
eind = start + (2 - 1) /* strlen("//") - 1 */;
|
2012-03-11 19:09:01 +00:00
|
|
|
memmove(start, eind, strlen(eind) + 1);
|
2005-12-14 13:21:32 +00:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-10-17 16:04:54 +11:00
|
|
|
/**
|
|
|
|
* Cleanup filepath ensuring a trailing slash.
|
|
|
|
*/
|
2011-03-11 00:30:51 +00:00
|
|
|
void BLI_cleanup_dir(const char *relabase, char *dir)
|
|
|
|
{
|
|
|
|
BLI_cleanup_path(relabase, dir);
|
|
|
|
BLI_add_slash(dir);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2015-10-17 16:04:54 +11:00
|
|
|
/**
|
|
|
|
* Cleanup filepath ensuring no trailing slash.
|
|
|
|
*/
|
2013-03-05 04:35:14 +00:00
|
|
|
void BLI_cleanup_file(const char *relabase, char *path)
|
2011-03-11 00:30:51 +00:00
|
|
|
{
|
2013-03-05 04:35:14 +00:00
|
|
|
BLI_cleanup_path(relabase, path);
|
|
|
|
BLI_del_slash(path);
|
2011-03-11 00:30:51 +00:00
|
|
|
}
|
2005-12-14 13:21:32 +00:00
|
|
|
|
2015-01-16 18:48:59 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Make given name safe to be used in paths.
|
|
|
|
*
|
2015-07-14 18:42:22 +02:00
|
|
|
* \return true if \a fname was changed, false otherwise.
|
|
|
|
*
|
2015-01-16 18:48:59 +01:00
|
|
|
* For now, simply replaces reserved chars (as listed in
|
2016-10-25 17:32:58 +02:00
|
|
|
* https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
|
2015-01-16 18:48:59 +01:00
|
|
|
* by underscores ('_').
|
2015-07-14 18:42:22 +02:00
|
|
|
*
|
|
|
|
* \note Space case ' ' is a bit of an edge case here - in theory it is allowed, but again can be an issue
|
|
|
|
* in some cases, so we simply replace it by an underscore too (good practice anyway).
|
2015-10-15 07:44:25 +02:00
|
|
|
* REMOVED based on popular demand (see T45900).
|
2015-10-18 18:51:08 +02:00
|
|
|
* Percent '%' char is a bit same case - not recommended to use it, but supported by all decent FS/OS around...
|
2015-07-14 18:42:22 +02:00
|
|
|
*
|
|
|
|
* \note On Windows, it also ensures there is no '.' (dot char) at the end of the file, this can lead to issues...
|
|
|
|
*
|
|
|
|
* \note On Windows, it also checks for forbidden names
|
|
|
|
* (see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx ).
|
2015-01-16 18:48:59 +01:00
|
|
|
*/
|
2015-07-14 18:42:22 +02:00
|
|
|
bool BLI_filename_make_safe(char *fname)
|
2015-01-16 18:48:59 +01:00
|
|
|
{
|
2015-10-15 07:44:25 +02:00
|
|
|
const char *invalid = "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
|
2015-07-14 18:42:22 +02:00
|
|
|
"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
|
2015-10-18 18:51:08 +02:00
|
|
|
"/\\?*:|\"<>";
|
2015-07-14 18:42:22 +02:00
|
|
|
char *fn;
|
|
|
|
bool changed = false;
|
|
|
|
|
|
|
|
if (*fname == '\0') {
|
|
|
|
return changed;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (fn = fname; *fn && (fn = strpbrk(fn, invalid)); fn++) {
|
|
|
|
*fn = '_';
|
|
|
|
changed = true;
|
|
|
|
}
|
2015-01-16 18:48:59 +01:00
|
|
|
|
2015-07-14 18:42:22 +02:00
|
|
|
/* Forbid only dots. */
|
|
|
|
for (fn = fname; *fn == '.'; fn++);
|
|
|
|
if (*fn == '\0') {
|
2015-01-16 18:48:59 +01:00
|
|
|
*fname = '_';
|
2015-07-14 18:42:22 +02:00
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
{
|
|
|
|
const size_t len = strlen(fname);
|
|
|
|
const char *invalid_names[] = {
|
|
|
|
"con", "prn", "aux", "null",
|
|
|
|
"com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9",
|
|
|
|
"lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9",
|
|
|
|
NULL
|
|
|
|
};
|
|
|
|
char *lower_fname = BLI_strdup(fname);
|
|
|
|
const char **iname;
|
|
|
|
|
|
|
|
/* Forbid trailing dot (trailing space has already been replaced above). */
|
|
|
|
if (fname[len - 1] == '.') {
|
|
|
|
fname[len - 1] = '_';
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Check for forbidden names - not we have to check all combination of upper and lower cases, hence the usage
|
|
|
|
* of lower_fname (more efficient than using BLI_strcasestr repeatedly). */
|
|
|
|
BLI_str_tolower_ascii(lower_fname, len);
|
|
|
|
for (iname = invalid_names; *iname; iname++) {
|
|
|
|
if (strstr(lower_fname, *iname) == lower_fname) {
|
|
|
|
const size_t iname_len = strlen(*iname);
|
|
|
|
/* Only invalid if the whole name is made of the invalid chunk, or it has an (assumed extension) dot
|
|
|
|
* just after. This means it will also catch 'valid' names like 'aux.foo.bar', but should be
|
|
|
|
* good enough for us! */
|
|
|
|
if ((iname_len == len) || (lower_fname[iname_len] == '.')) {
|
|
|
|
*fname = '_';
|
|
|
|
changed = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
MEM_freeN(lower_fname);
|
2015-01-16 18:48:59 +01:00
|
|
|
}
|
2015-07-14 18:42:22 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return changed;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Make given path OS-safe.
|
|
|
|
*
|
|
|
|
* \return true if \a path was changed, false otherwise.
|
|
|
|
*/
|
|
|
|
bool BLI_path_make_safe(char *path)
|
|
|
|
{
|
|
|
|
/* Simply apply BLI_filename_make_safe() over each component of the path.
|
2015-10-07 15:02:06 +11:00
|
|
|
* Luckily enough, same 'safe' rules applies to filenames and dirnames. */
|
2015-07-14 18:42:22 +02:00
|
|
|
char *curr_slash, *curr_path = path;
|
|
|
|
bool changed = false;
|
|
|
|
bool skip_first = false;
|
|
|
|
|
|
|
|
#ifdef WIN32
|
|
|
|
if (BLI_path_is_abs(path)) {
|
|
|
|
/* Do not make safe 'C:' in 'C:\foo\bar'... */
|
|
|
|
skip_first = true;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
for (curr_slash = (char *)BLI_first_slash(curr_path); curr_slash; curr_slash = (char *)BLI_first_slash(curr_path)) {
|
|
|
|
const char backup = *curr_slash;
|
|
|
|
*curr_slash = '\0';
|
|
|
|
if (!skip_first && (*curr_path != '\0') && BLI_filename_make_safe(curr_path)) {
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
skip_first = false;
|
|
|
|
curr_path = curr_slash + 1;
|
|
|
|
*curr_slash = backup;
|
|
|
|
}
|
|
|
|
if (BLI_filename_make_safe(curr_path)) {
|
|
|
|
changed = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return changed;
|
2015-01-16 18:48:59 +01:00
|
|
|
}
|
|
|
|
|
2013-03-04 19:27:51 +00:00
|
|
|
/**
|
|
|
|
* Does path begin with the special "//" prefix that Blender uses to indicate
|
|
|
|
* a path relative to the .blend file.
|
|
|
|
*/
|
|
|
|
bool BLI_path_is_rel(const char *path)
|
2012-08-29 10:32:38 +00:00
|
|
|
{
|
|
|
|
return path[0] == '/' && path[1] == '/';
|
|
|
|
}
|
|
|
|
|
2014-04-21 16:49:35 +02:00
|
|
|
/* return true if the path is a UNC share */
|
|
|
|
bool BLI_path_is_unc(const char *name)
|
|
|
|
{
|
|
|
|
return name[0] == '\\' && name[1] == '\\';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the length of the identifying prefix
|
|
|
|
* of a UNC path which can start with '\\' (short version)
|
|
|
|
* or '\\?\' (long version)
|
|
|
|
* If the path is not a UNC path, return 0
|
|
|
|
*/
|
|
|
|
static int BLI_path_unc_prefix_len(const char *path)
|
|
|
|
{
|
|
|
|
if (BLI_path_is_unc(path)) {
|
|
|
|
if ((path[2] == '?') && (path[3] == '\\') ) {
|
|
|
|
/* we assume long UNC path like \\?\server\share\folder etc... */
|
|
|
|
return 4;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if defined(WIN32)
|
|
|
|
|
|
|
|
/* return true if the path is absolute ie starts with a drive specifier (eg A:\) or is a UNC path */
|
|
|
|
static bool BLI_path_is_abs(const char *name)
|
|
|
|
{
|
|
|
|
return (name[1] == ':' && (name[2] == '\\' || name[2] == '/') ) || BLI_path_is_unc(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
static wchar_t *next_slash(wchar_t *path)
|
|
|
|
{
|
|
|
|
wchar_t *slash = path;
|
|
|
|
while (*slash && *slash != L'\\') slash++;
|
|
|
|
return slash;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* adds a slash if the unc path points sto a share */
|
|
|
|
static void BLI_path_add_slash_to_share(wchar_t *uncpath)
|
|
|
|
{
|
|
|
|
wchar_t *slash_after_server = next_slash(uncpath + 2);
|
|
|
|
if (*slash_after_server) {
|
|
|
|
wchar_t *slash_after_share = next_slash(slash_after_server + 1);
|
|
|
|
if (!(*slash_after_share)) {
|
|
|
|
slash_after_share[0] = L'\\';
|
|
|
|
slash_after_share[1] = L'\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void BLI_path_unc_to_short(wchar_t *unc)
|
|
|
|
{
|
|
|
|
wchar_t tmp[PATH_MAX];
|
|
|
|
|
|
|
|
int len = wcslen(unc);
|
|
|
|
int copy_start = 0;
|
|
|
|
/* convert:
|
|
|
|
* \\?\UNC\server\share\folder\... to \\server\share\folder\...
|
|
|
|
* \\?\C:\ to C:\ and \\?\C:\folder\... to C:\folder\...
|
|
|
|
*/
|
|
|
|
if ((len > 3) &&
|
|
|
|
(unc[0] == L'\\') &&
|
|
|
|
(unc[1] == L'\\') &&
|
|
|
|
(unc[2] == L'?') &&
|
|
|
|
((unc[3] == L'\\') || (unc[3] == L'/')))
|
|
|
|
{
|
|
|
|
if ((len > 5) && (unc[5] == L':')) {
|
|
|
|
wcsncpy(tmp, unc + 4, len - 4);
|
|
|
|
tmp[len - 4] = L'\0';
|
|
|
|
wcscpy(unc, tmp);
|
|
|
|
}
|
|
|
|
else if ((len > 7) && (wcsncmp(&unc[4], L"UNC", 3) == 0) &&
|
|
|
|
((unc[7] == L'\\') || (unc[7] == L'/')))
|
|
|
|
{
|
|
|
|
tmp[0] = L'\\';
|
|
|
|
tmp[1] = L'\\';
|
|
|
|
wcsncpy(tmp + 2, unc + 8, len - 8);
|
|
|
|
tmp[len - 6] = L'\0';
|
|
|
|
wcscpy(unc, tmp);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void BLI_cleanup_unc(char *path, int maxlen)
|
|
|
|
{
|
|
|
|
wchar_t *tmp_16 = alloc_utf16_from_8(path, 1);
|
|
|
|
BLI_cleanup_unc_16(tmp_16);
|
|
|
|
conv_utf_16_to_8(tmp_16, path, maxlen);
|
|
|
|
}
|
|
|
|
|
|
|
|
void BLI_cleanup_unc_16(wchar_t *path_16)
|
|
|
|
{
|
|
|
|
BLI_path_unc_to_short(path_16);
|
|
|
|
BLI_path_add_slash_to_share(path_16);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-03-05 03:17:46 +00:00
|
|
|
/**
|
|
|
|
* Replaces *file with a relative version (prefixed by "//") such that BLI_path_abs, given
|
|
|
|
* the same *relfile, will convert it back to its original value.
|
|
|
|
*/
|
2010-03-09 17:36:23 +00:00
|
|
|
void BLI_path_rel(char *file, const char *relfile)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2013-03-04 19:27:51 +00:00
|
|
|
const char *lslash;
|
2011-11-26 04:07:38 +00:00
|
|
|
char temp[FILE_MAX];
|
|
|
|
char res[FILE_MAX];
|
2008-04-28 21:29:15 +00:00
|
|
|
|
2005-12-11 22:03:04 +00:00
|
|
|
/* if file is already relative, bail out */
|
2012-08-29 10:32:38 +00:00
|
|
|
if (BLI_path_is_rel(file)) {
|
|
|
|
return;
|
|
|
|
}
|
2005-12-11 22:03:04 +00:00
|
|
|
|
2006-08-20 14:41:13 +00:00
|
|
|
/* also bail out if relative path is not set */
|
2012-08-29 10:32:38 +00:00
|
|
|
if (relfile[0] == '\0') {
|
|
|
|
return;
|
|
|
|
}
|
2006-08-20 14:41:13 +00:00
|
|
|
|
2010-12-05 23:50:55 +00:00
|
|
|
#ifdef WIN32
|
2014-04-21 16:49:35 +02:00
|
|
|
if (BLI_strnlen(relfile, 3) > 2 && !BLI_path_is_abs(relfile)) {
|
2012-05-12 15:13:06 +00:00
|
|
|
char *ptemp;
|
2007-02-21 20:00:03 +00:00
|
|
|
/* fix missing volume name in relative base,
|
2012-03-03 20:19:11 +00:00
|
|
|
* can happen with old recent-files.txt files */
|
2007-02-21 20:00:03 +00:00
|
|
|
get_default_root(temp);
|
|
|
|
ptemp = &temp[2];
|
|
|
|
if (relfile[0] != '\\' && relfile[0] != '/') {
|
|
|
|
ptemp++;
|
|
|
|
}
|
2012-05-12 15:13:06 +00:00
|
|
|
BLI_strncpy(ptemp, relfile, FILE_MAX - 3);
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2011-11-26 04:07:38 +00:00
|
|
|
BLI_strncpy(temp, relfile, FILE_MAX);
|
2007-02-21 20:00:03 +00:00
|
|
|
}
|
|
|
|
|
2010-12-05 23:50:55 +00:00
|
|
|
if (BLI_strnlen(file, 3) > 2) {
|
2014-04-21 16:49:35 +02:00
|
|
|
bool is_unc = BLI_path_is_unc(file);
|
|
|
|
|
|
|
|
/* Ensure paths are both UNC paths or are both drives */
|
|
|
|
if (BLI_path_is_unc(temp) != is_unc) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Ensure both UNC paths are on the same share */
|
|
|
|
if (is_unc) {
|
|
|
|
int off;
|
|
|
|
int slash = 0;
|
|
|
|
for (off = 0; temp[off] && slash < 4; off++) {
|
|
|
|
if (temp[off] != file[off])
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (temp[off] == '\\')
|
|
|
|
slash++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (temp[1] == ':' && file[1] == ':' && temp[0] != file[0]) {
|
2005-10-24 20:52:51 +00:00
|
|
|
return;
|
2014-04-21 16:49:35 +02:00
|
|
|
}
|
2005-10-24 20:52:51 +00:00
|
|
|
}
|
2007-02-21 20:00:03 +00:00
|
|
|
#else
|
|
|
|
BLI_strncpy(temp, relfile, FILE_MAX);
|
2005-05-20 12:18:11 +00:00
|
|
|
#endif
|
2005-10-24 20:52:51 +00:00
|
|
|
|
2015-06-30 15:18:03 +10:00
|
|
|
BLI_str_replace_char(temp + BLI_path_unc_prefix_len(temp), '\\', '/');
|
|
|
|
BLI_str_replace_char(file + BLI_path_unc_prefix_len(file), '\\', '/');
|
2008-04-28 21:29:15 +00:00
|
|
|
|
|
|
|
/* remove /./ which confuse the following slash counting... */
|
2011-03-11 00:30:51 +00:00
|
|
|
BLI_cleanup_path(NULL, file);
|
|
|
|
BLI_cleanup_path(NULL, temp);
|
2008-04-28 21:29:15 +00:00
|
|
|
|
2005-10-24 20:52:51 +00:00
|
|
|
/* the last slash in the file indicates where the path part ends */
|
|
|
|
lslash = BLI_last_slash(temp);
|
|
|
|
|
2012-03-06 18:40:15 +00:00
|
|
|
if (lslash) {
|
2005-10-24 20:52:51 +00:00
|
|
|
/* find the prefix of the filename that is equal for both filenames.
|
2012-03-03 20:19:11 +00:00
|
|
|
* This is replaced by the two slashes at the beginning */
|
2014-04-27 00:20:55 +10:00
|
|
|
const char *p = temp;
|
|
|
|
const char *q = file;
|
2013-06-27 20:47:59 +00:00
|
|
|
char *r = res;
|
2010-06-03 13:05:45 +00:00
|
|
|
|
2011-04-08 06:47:41 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
while (tolower(*p) == tolower(*q))
|
|
|
|
#else
|
|
|
|
while (*p == *q)
|
|
|
|
#endif
|
|
|
|
{
|
2012-05-09 09:24:15 +00:00
|
|
|
p++;
|
|
|
|
q++;
|
|
|
|
|
2012-03-18 07:38:51 +00:00
|
|
|
/* don't search beyond the end of the string
|
2010-06-03 13:05:45 +00:00
|
|
|
* in the rare case they match */
|
2012-05-12 15:13:06 +00:00
|
|
|
if ((*p == '\0') || (*q == '\0')) {
|
2010-06-03 13:05:45 +00:00
|
|
|
break;
|
|
|
|
}
|
2005-10-24 20:52:51 +00:00
|
|
|
}
|
2010-06-03 13:05:45 +00:00
|
|
|
|
2005-10-24 20:52:51 +00:00
|
|
|
/* we might have passed the slash when the beginning of a dir matches
|
2012-03-03 20:19:11 +00:00
|
|
|
* so we rewind. Only check on the actual filename
|
|
|
|
*/
|
2005-10-24 20:52:51 +00:00
|
|
|
if (*q != '/') {
|
|
|
|
while ( (q >= file) && (*q != '/') ) { --q; --p; }
|
2012-10-21 05:46:41 +00:00
|
|
|
}
|
2005-10-24 20:52:51 +00:00
|
|
|
else if (*p != '/') {
|
|
|
|
while ( (p >= temp) && (*p != '/') ) { --p; --q; }
|
|
|
|
}
|
|
|
|
|
2013-06-27 20:47:59 +00:00
|
|
|
r += BLI_strcpy_rlen(r, "//");
|
2005-10-24 20:52:51 +00:00
|
|
|
|
|
|
|
/* p now points to the slash that is at the beginning of the part
|
2012-03-03 20:19:11 +00:00
|
|
|
* where the path is different from the relative path.
|
|
|
|
* We count the number of directories we need to go up in the
|
|
|
|
* hierarchy to arrive at the common 'prefix' of the path
|
|
|
|
*/
|
2013-06-27 20:47:59 +00:00
|
|
|
if (p < temp) p = temp;
|
2012-05-12 15:13:06 +00:00
|
|
|
while (p && p < lslash) {
|
2013-06-27 20:47:59 +00:00
|
|
|
if (*p == '/') {
|
|
|
|
r += BLI_strcpy_rlen(r, "../");
|
|
|
|
}
|
2012-05-09 09:24:15 +00:00
|
|
|
p++;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2005-10-24 20:52:51 +00:00
|
|
|
|
2013-06-27 20:47:59 +00:00
|
|
|
/* don't copy the slash at the beginning */
|
|
|
|
r += BLI_strcpy_rlen(r, q + 1);
|
2005-12-14 13:21:32 +00:00
|
|
|
|
2012-05-12 15:13:06 +00:00
|
|
|
#ifdef WIN32
|
2015-06-30 15:18:03 +10:00
|
|
|
BLI_str_replace_char(res + 2, '/', '\\');
|
2005-10-24 20:52:51 +00:00
|
|
|
#endif
|
|
|
|
strcpy(file, res);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-16 14:25:23 -03:00
|
|
|
/**
|
|
|
|
* Appends a suffix to the string, fitting it before the extension
|
|
|
|
*
|
|
|
|
* string = Foo.png, suffix = 123, separator = _
|
|
|
|
* Foo.png -> Foo_123.png
|
|
|
|
*
|
|
|
|
* \param string original (and final) string
|
|
|
|
* \param maxlen Maximum length of string
|
|
|
|
* \param suffix String to append to the original string
|
|
|
|
* \param sep Optional separator character
|
2014-05-08 04:53:05 +10:00
|
|
|
* \return true if succeeded
|
2014-04-16 14:25:23 -03:00
|
|
|
*/
|
|
|
|
bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char *sep)
|
|
|
|
{
|
|
|
|
const size_t string_len = strlen(string);
|
|
|
|
const size_t suffix_len = strlen(suffix);
|
|
|
|
const size_t sep_len = strlen(sep);
|
|
|
|
ssize_t a;
|
|
|
|
char extension[FILE_MAX];
|
|
|
|
bool has_extension = false;
|
|
|
|
|
|
|
|
if (string_len + sep_len + suffix_len >= maxlen)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
for (a = string_len - 1; a >= 0; a--) {
|
|
|
|
if (string[a] == '.') {
|
|
|
|
has_extension = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (ELEM(string[a], '/', '\\')) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!has_extension)
|
|
|
|
a = string_len;
|
|
|
|
|
|
|
|
BLI_strncpy(extension, string + a, sizeof(extension));
|
|
|
|
sprintf(string + a, "%s%s%s", sep, suffix, extension);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-03-04 19:27:51 +00:00
|
|
|
/**
|
2013-03-05 03:17:46 +00:00
|
|
|
* Replaces path with the path of its parent directory, returning true if
|
2013-03-04 19:27:51 +00:00
|
|
|
* it was able to find a parent directory within the pathname.
|
|
|
|
*/
|
|
|
|
bool BLI_parent_dir(char *path)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2014-01-31 03:28:53 +11:00
|
|
|
const char parent_dir[] = {'.', '.', SEP, '\0'}; /* "../" or "..\\" */
|
2012-05-12 15:13:06 +00:00
|
|
|
char tmp[FILE_MAX + 4];
|
2013-07-19 10:39:49 +00:00
|
|
|
|
|
|
|
BLI_join_dirfile(tmp, sizeof(tmp), path, parent_dir);
|
2013-03-04 19:27:51 +00:00
|
|
|
BLI_cleanup_dir(NULL, tmp); /* does all the work of normalizing the path for us */
|
2011-04-21 15:53:30 +00:00
|
|
|
|
2008-09-22 21:15:48 +00:00
|
|
|
if (!BLI_testextensie(tmp, parent_dir)) {
|
2015-04-08 21:57:49 +02:00
|
|
|
strcpy(path, tmp); /* We assume pardir is always shorter... */
|
2013-03-04 19:27:51 +00:00
|
|
|
return true;
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-03-04 19:27:51 +00:00
|
|
|
return false;
|
2008-09-22 15:37:32 +00:00
|
|
|
}
|
|
|
|
}
|
2008-05-04 09:41:15 +00:00
|
|
|
|
2013-03-04 19:27:51 +00:00
|
|
|
/**
|
|
|
|
* Looks for a sequence of "#" characters in the last slash-separated component of *path,
|
|
|
|
* returning the indexes of the first and one past the last character in the sequence in
|
2013-03-05 03:17:46 +00:00
|
|
|
* *char_start and *char_end respectively. Returns true if such a sequence was found.
|
2013-03-04 19:27:51 +00:00
|
|
|
*/
|
|
|
|
static bool stringframe_chars(const char *path, int *char_start, int *char_end)
|
2008-05-04 09:41:15 +00:00
|
|
|
{
|
2017-10-28 17:48:45 +11:00
|
|
|
uint ch_sta, ch_end, i;
|
2008-05-04 09:41:15 +00:00
|
|
|
/* Insert current frame: file### -> file001 */
|
|
|
|
ch_sta = ch_end = 0;
|
|
|
|
for (i = 0; path[i] != '\0'; i++) {
|
|
|
|
if (path[i] == '\\' || path[i] == '/') {
|
2012-03-18 07:38:51 +00:00
|
|
|
ch_end = 0; /* this is a directory name, don't use any hashes we found */
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
else if (path[i] == '#') {
|
2008-05-04 09:41:15 +00:00
|
|
|
ch_sta = i;
|
2012-05-12 15:13:06 +00:00
|
|
|
ch_end = ch_sta + 1;
|
2008-05-04 09:41:15 +00:00
|
|
|
while (path[ch_end] == '#') {
|
|
|
|
ch_end++;
|
|
|
|
}
|
2012-05-12 15:13:06 +00:00
|
|
|
i = ch_end - 1; /* keep searching */
|
2008-05-04 09:41:15 +00:00
|
|
|
|
2012-03-18 07:38:51 +00:00
|
|
|
/* don't break, there may be a slash after this that invalidates the previous #'s */
|
2008-05-04 09:41:15 +00:00
|
|
|
}
|
|
|
|
}
|
2010-01-26 21:41:38 +00:00
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (ch_end) {
|
2012-05-12 15:13:06 +00:00
|
|
|
*char_start = ch_sta;
|
|
|
|
*char_end = ch_end;
|
2013-03-04 19:27:51 +00:00
|
|
|
return true;
|
2010-01-26 21:41:38 +00:00
|
|
|
}
|
|
|
|
else {
|
2012-05-12 15:13:06 +00:00
|
|
|
*char_start = -1;
|
|
|
|
*char_end = -1;
|
2013-03-04 19:27:51 +00:00
|
|
|
return false;
|
2010-01-26 21:41:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-04 19:27:51 +00:00
|
|
|
/**
|
|
|
|
* Ensure *path contains at least one "#" character in its last slash-separated
|
|
|
|
* component, appending one digits long if not.
|
|
|
|
*/
|
2010-01-30 22:33:47 +00:00
|
|
|
static void ensure_digits(char *path, int digits)
|
|
|
|
{
|
2013-03-04 19:27:51 +00:00
|
|
|
char *file = (char *)BLI_last_slash(path);
|
2010-01-30 22:33:47 +00:00
|
|
|
|
2012-05-12 15:13:06 +00:00
|
|
|
if (file == NULL)
|
|
|
|
file = path;
|
2010-01-30 22:33:47 +00:00
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (strrchr(file, '#') == NULL) {
|
2012-05-12 15:13:06 +00:00
|
|
|
int len = strlen(file);
|
2010-01-30 22:33:47 +00:00
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
while (digits--) {
|
2012-05-12 15:13:06 +00:00
|
|
|
file[len++] = '#';
|
2010-01-30 22:33:47 +00:00
|
|
|
}
|
2012-05-12 15:13:06 +00:00
|
|
|
file[len] = '\0';
|
2010-01-30 22:33:47 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-05 03:17:46 +00:00
|
|
|
/**
|
|
|
|
* Replaces "#" character sequence in last slash-separated component of *path
|
|
|
|
* with frame as decimal integer, with leading zeroes as necessary, to make digits digits.
|
|
|
|
*/
|
|
|
|
bool BLI_path_frame(char *path, int frame, int digits)
|
2010-01-26 21:41:38 +00:00
|
|
|
{
|
|
|
|
int ch_sta, ch_end;
|
2010-01-30 22:33:47 +00:00
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (digits)
|
2010-01-30 22:33:47 +00:00
|
|
|
ensure_digits(path, digits);
|
|
|
|
|
2010-01-26 21:41:38 +00:00
|
|
|
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */
|
2010-11-01 01:46:26 +00:00
|
|
|
char tmp[FILE_MAX];
|
2013-07-23 12:49:30 +00:00
|
|
|
BLI_snprintf(tmp, sizeof(tmp),
|
|
|
|
"%.*s%.*d%s",
|
|
|
|
ch_sta, path, ch_end - ch_sta, frame, path + ch_end);
|
|
|
|
BLI_strncpy(path, tmp, FILE_MAX);
|
2013-03-05 03:17:46 +00:00
|
|
|
return true;
|
2008-05-04 09:41:15 +00:00
|
|
|
}
|
2013-03-05 03:17:46 +00:00
|
|
|
return false;
|
2008-05-04 09:41:15 +00:00
|
|
|
}
|
2006-09-16 11:42:37 +00:00
|
|
|
|
2013-03-05 03:17:46 +00:00
|
|
|
/**
|
|
|
|
* Replaces "#" character sequence in last slash-separated component of *path
|
|
|
|
* with sta and end as decimal integers, with leading zeroes as necessary, to make digits
|
|
|
|
* digits each, with a hyphen in-between.
|
|
|
|
*/
|
|
|
|
bool BLI_path_frame_range(char *path, int sta, int end, int digits)
|
2010-01-26 21:41:38 +00:00
|
|
|
{
|
|
|
|
int ch_sta, ch_end;
|
2010-01-30 22:33:47 +00:00
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (digits)
|
2010-01-30 22:33:47 +00:00
|
|
|
ensure_digits(path, digits);
|
|
|
|
|
2010-01-26 21:41:38 +00:00
|
|
|
if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */
|
2011-03-29 14:07:07 +00:00
|
|
|
char tmp[FILE_MAX];
|
2012-01-11 12:33:51 +00:00
|
|
|
BLI_snprintf(tmp, sizeof(tmp),
|
|
|
|
"%.*s%.*d-%.*d%s",
|
2012-05-12 15:13:06 +00:00
|
|
|
ch_sta, path, ch_end - ch_sta, sta, ch_end - ch_sta, end, path + ch_end);
|
2012-01-11 12:33:51 +00:00
|
|
|
BLI_strncpy(path, tmp, FILE_MAX);
|
2013-03-05 03:17:46 +00:00
|
|
|
return true;
|
2010-01-26 21:41:38 +00:00
|
|
|
}
|
2013-03-05 03:17:46 +00:00
|
|
|
return false;
|
2010-01-26 21:41:38 +00:00
|
|
|
}
|
2006-08-20 14:41:13 +00:00
|
|
|
|
2015-06-04 20:40:11 +02:00
|
|
|
/**
|
|
|
|
* Get the frame from a filename formatted by blender's frame scheme
|
|
|
|
*/
|
|
|
|
bool BLI_path_frame_get(char *path, int *r_frame, int *r_numdigits)
|
|
|
|
{
|
2015-10-17 16:06:45 +11:00
|
|
|
if (*path) {
|
2015-06-04 20:40:11 +02:00
|
|
|
char *file = (char *)BLI_last_slash(path);
|
|
|
|
char *c;
|
|
|
|
int len, numdigits;
|
|
|
|
|
|
|
|
numdigits = *r_numdigits = 0;
|
|
|
|
|
|
|
|
if (file == NULL)
|
|
|
|
file = path;
|
|
|
|
|
|
|
|
/* first get the extension part */
|
|
|
|
len = strlen(file);
|
|
|
|
|
|
|
|
c = file + len;
|
|
|
|
|
|
|
|
/* isolate extension */
|
|
|
|
while (--c != file) {
|
|
|
|
if (*c == '.') {
|
|
|
|
c--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* find start of number */
|
|
|
|
while (c != (file - 1) && isdigit(*c)) {
|
|
|
|
c--;
|
|
|
|
numdigits++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (numdigits) {
|
|
|
|
char prevchar;
|
|
|
|
|
|
|
|
c++;
|
|
|
|
prevchar = c[numdigits];
|
|
|
|
c[numdigits] = 0;
|
|
|
|
|
|
|
|
/* was the number really an extension? */
|
|
|
|
*r_frame = atoi(c);
|
|
|
|
c[numdigits] = prevchar;
|
|
|
|
|
|
|
|
*r_numdigits = numdigits;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-10-17 16:06:45 +11:00
|
|
|
void BLI_path_frame_strip(char *path, bool set_frame_char, char *ext)
|
2015-06-04 20:40:11 +02:00
|
|
|
{
|
2015-10-17 16:06:45 +11:00
|
|
|
if (*path) {
|
2015-06-04 20:40:11 +02:00
|
|
|
char *file = (char *)BLI_last_slash(path);
|
|
|
|
char *c, *suffix;
|
|
|
|
int len;
|
|
|
|
int numdigits = 0;
|
|
|
|
|
|
|
|
if (file == NULL)
|
|
|
|
file = path;
|
|
|
|
|
|
|
|
/* first get the extension part */
|
|
|
|
len = strlen(file);
|
|
|
|
|
|
|
|
c = file + len;
|
|
|
|
|
|
|
|
/* isolate extension */
|
|
|
|
while (--c != file) {
|
|
|
|
if (*c == '.') {
|
|
|
|
c--;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
suffix = c + 1;
|
|
|
|
|
|
|
|
/* find start of number */
|
|
|
|
while (c != (file - 1) && isdigit(*c)) {
|
|
|
|
c--;
|
|
|
|
numdigits++;
|
|
|
|
}
|
|
|
|
|
|
|
|
c++;
|
|
|
|
|
2015-06-06 21:02:16 +10:00
|
|
|
if (numdigits) {
|
2015-06-04 20:40:11 +02:00
|
|
|
/* replace the number with the suffix and terminate the string */
|
|
|
|
while (numdigits--) {
|
2015-10-17 16:06:45 +11:00
|
|
|
*ext++ = *suffix;
|
|
|
|
*c++ = set_frame_char ? '#' : *suffix;
|
2015-06-04 20:40:11 +02:00
|
|
|
suffix++;
|
|
|
|
}
|
2015-10-17 16:06:45 +11:00
|
|
|
*c = '\0';
|
|
|
|
*ext = '\0';
|
2015-06-04 20:40:11 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-11-25 16:59:10 +11:00
|
|
|
/**
|
|
|
|
* Check if we have '#' chars, usable for #BLI_path_frame, #BLI_path_frame_range
|
|
|
|
*/
|
|
|
|
bool BLI_path_frame_check_chars(const char *path)
|
|
|
|
{
|
|
|
|
int ch_sta, ch_end; /* dummy args */
|
|
|
|
return stringframe_chars(path, &ch_sta, &ch_end);
|
|
|
|
}
|
|
|
|
|
2013-03-04 19:27:51 +00:00
|
|
|
/**
|
2015-10-17 16:04:54 +11:00
|
|
|
* If path begins with "//", strips that and replaces it with basepath directory.
|
|
|
|
*
|
|
|
|
* \note Also converts drive-letter prefix to something more sensible
|
|
|
|
* if this is a non-drive-letter-based system.
|
|
|
|
*
|
|
|
|
* \param path: The path to convert.
|
|
|
|
* \param basepath: The directory to base relative paths with.
|
|
|
|
* \return true if the path was relative (started with "//").
|
2013-03-04 19:27:51 +00:00
|
|
|
*/
|
|
|
|
bool BLI_path_abs(char *path, const char *basepath)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2013-03-04 19:27:51 +00:00
|
|
|
const bool wasrelative = BLI_path_is_rel(path);
|
2008-03-30 16:18:01 +00:00
|
|
|
char tmp[FILE_MAX];
|
|
|
|
char base[FILE_MAX];
|
2006-08-20 14:41:13 +00:00
|
|
|
#ifdef WIN32
|
2006-09-16 11:42:37 +00:00
|
|
|
|
2014-09-22 14:42:07 +10:00
|
|
|
/* without this: "" --> "C:\" */
|
|
|
|
if (*path == '\0') {
|
|
|
|
return wasrelative;
|
|
|
|
}
|
|
|
|
|
2006-09-16 11:42:37 +00:00
|
|
|
/* we are checking here if we have an absolute path that is not in the current
|
2012-03-03 20:19:11 +00:00
|
|
|
* blend file as a lib main - we are basically checking for the case that a
|
|
|
|
* UNIX root '/' is passed.
|
|
|
|
*/
|
2014-04-21 16:49:35 +02:00
|
|
|
if (!wasrelative && !BLI_path_is_abs(path)) {
|
2006-09-16 11:42:37 +00:00
|
|
|
char *p = path;
|
2006-08-20 14:41:13 +00:00
|
|
|
get_default_root(tmp);
|
|
|
|
// get rid of the slashes at the beginning of the path
|
2006-09-16 11:42:37 +00:00
|
|
|
while (*p == '\\' || *p == '/') {
|
|
|
|
p++;
|
2006-08-20 14:41:13 +00:00
|
|
|
}
|
2006-09-16 11:42:37 +00:00
|
|
|
strcat(tmp, p);
|
2006-08-20 14:41:13 +00:00
|
|
|
}
|
|
|
|
else {
|
2008-03-30 16:18:01 +00:00
|
|
|
BLI_strncpy(tmp, path, FILE_MAX);
|
2006-08-20 14:41:13 +00:00
|
|
|
}
|
|
|
|
#else
|
2010-08-12 03:37:45 +00:00
|
|
|
BLI_strncpy(tmp, path, sizeof(tmp));
|
2008-09-30 04:08:00 +00:00
|
|
|
|
|
|
|
/* Check for loading a windows path on a posix system
|
|
|
|
* in this case, there is no use in trying C:/ since it
|
|
|
|
* will never exist on a unix os.
|
|
|
|
*
|
|
|
|
* Add a / prefix and lowercase the driveletter, remove the :
|
|
|
|
* C:\foo.JPG -> /c/foo.JPG */
|
|
|
|
|
2012-05-12 15:13:06 +00:00
|
|
|
if (isalpha(tmp[0]) && tmp[1] == ':' && (tmp[2] == '\\' || tmp[2] == '/') ) {
|
2008-09-30 04:08:00 +00:00
|
|
|
tmp[1] = tolower(tmp[0]); /* replace ':' with driveletter */
|
|
|
|
tmp[0] = '/';
|
|
|
|
/* '\' the slash will be converted later */
|
|
|
|
}
|
|
|
|
|
2006-08-20 14:41:13 +00:00
|
|
|
#endif
|
|
|
|
|
2005-05-20 12:18:11 +00:00
|
|
|
/* push slashes into unix mode - strings entering this part are
|
2012-03-03 20:19:11 +00:00
|
|
|
* potentially messed up: having both back- and forward slashes.
|
|
|
|
* Here we push into one conform direction, and at the end we
|
|
|
|
* push them into the system specific dir. This ensures uniformity
|
|
|
|
* of paths and solving some problems (and prevent potential future
|
2014-04-21 16:49:35 +02:00
|
|
|
* ones) -jesterKing.
|
|
|
|
* For UNC paths the first characters containing the UNC prefix
|
|
|
|
* shouldn't be switched as we need to distinguish them from
|
|
|
|
* paths relative to the .blend file -elubie */
|
2015-06-30 15:18:03 +10:00
|
|
|
BLI_str_replace_char(tmp + BLI_path_unc_prefix_len(tmp), '\\', '/');
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2008-06-05 13:02:00 +00:00
|
|
|
/* Paths starting with // will get the blend file as their base,
|
2012-03-18 07:38:51 +00:00
|
|
|
* this isn't standard in any os but is used in blender all over the place */
|
2008-06-14 16:54:46 +00:00
|
|
|
if (wasrelative) {
|
2014-04-21 16:49:35 +02:00
|
|
|
const char *lslash;
|
|
|
|
BLI_strncpy(base, basepath, sizeof(base));
|
|
|
|
|
|
|
|
/* file component is ignored, so don't bother with the trailing slash */
|
|
|
|
BLI_cleanup_path(NULL, base);
|
|
|
|
lslash = BLI_last_slash(base);
|
2015-06-30 15:18:03 +10:00
|
|
|
BLI_str_replace_char(base + BLI_path_unc_prefix_len(base), '\\', '/');
|
2014-04-21 16:49:35 +02:00
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
if (lslash) {
|
2013-03-04 19:27:51 +00:00
|
|
|
const int baselen = (int) (lslash - base) + 1; /* length up to and including last "/" */
|
2010-04-25 15:24:18 +00:00
|
|
|
/* use path for temp storage here, we copy back over it right away */
|
2013-03-04 19:27:51 +00:00
|
|
|
BLI_strncpy(path, tmp + 2, FILE_MAX); /* strip "//" */
|
2008-06-05 13:02:00 +00:00
|
|
|
|
2013-03-04 19:27:51 +00:00
|
|
|
memcpy(tmp, base, baselen); /* prefix with base up to last "/" */
|
|
|
|
BLI_strncpy(tmp + baselen, path, sizeof(tmp) - baselen); /* append path after "//" */
|
|
|
|
BLI_strncpy(path, tmp, FILE_MAX); /* return as result */
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-03-04 19:27:51 +00:00
|
|
|
/* base doesn't seem to be a directory--ignore it and just strip "//" prefix on path */
|
2012-05-12 15:13:06 +00:00
|
|
|
BLI_strncpy(path, tmp + 2, FILE_MAX);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-03-04 19:27:51 +00:00
|
|
|
/* base ignored */
|
2010-08-12 03:37:45 +00:00
|
|
|
BLI_strncpy(path, tmp, FILE_MAX);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2011-03-11 01:06:16 +00:00
|
|
|
|
2005-05-20 12:18:11 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
/* skip first two chars, which in case of
|
2012-03-03 20:19:11 +00:00
|
|
|
* absolute path will be drive:/blabla and
|
|
|
|
* in case of relpath //blabla/. So relpath
|
|
|
|
* // will be retained, rest will be nice and
|
|
|
|
* shiny win32 backward slashes :) -jesterKing
|
|
|
|
*/
|
2015-06-30 15:18:03 +10:00
|
|
|
BLI_str_replace_char(path + 2, '/', '\\');
|
2005-05-20 12:18:11 +00:00
|
|
|
#endif
|
2014-12-01 16:01:08 +01:00
|
|
|
|
|
|
|
/* ensure this is after correcting for path switch */
|
|
|
|
BLI_cleanup_path(NULL, path);
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
return wasrelative;
|
|
|
|
}
|
|
|
|
|
2008-09-15 01:32:53 +00:00
|
|
|
|
2013-03-05 03:17:46 +00:00
|
|
|
/**
|
|
|
|
* Expands path relative to the current working directory, if it was relative.
|
|
|
|
* Returns true if such expansion was done.
|
|
|
|
*
|
|
|
|
* \note Should only be done with command line paths.
|
|
|
|
* this is _not_ something blenders internal paths support like the "//" prefix
|
2008-09-15 01:32:53 +00:00
|
|
|
*/
|
2015-10-08 15:05:58 +11:00
|
|
|
bool BLI_path_cwd(char *path, const size_t maxlen)
|
2008-09-15 01:32:53 +00:00
|
|
|
{
|
2013-03-05 03:17:46 +00:00
|
|
|
bool wasrelative = true;
|
|
|
|
const int filelen = strlen(path);
|
2008-09-15 01:32:53 +00:00
|
|
|
|
|
|
|
#ifdef WIN32
|
2014-04-21 16:49:35 +02:00
|
|
|
if ((filelen >= 3 && BLI_path_is_abs(path)) || BLI_path_is_unc(path))
|
2013-03-05 03:17:46 +00:00
|
|
|
wasrelative = false;
|
2008-09-15 01:32:53 +00:00
|
|
|
#else
|
|
|
|
if (filelen >= 2 && path[0] == '/')
|
2013-03-05 03:17:46 +00:00
|
|
|
wasrelative = false;
|
2008-09-15 01:32:53 +00:00
|
|
|
#endif
|
|
|
|
|
2013-03-05 03:17:46 +00:00
|
|
|
if (wasrelative) {
|
2015-10-08 15:05:58 +11:00
|
|
|
char cwd[FILE_MAX];
|
|
|
|
/* in case the full path to the blend isn't used */
|
|
|
|
if (BLI_current_working_dir(cwd, sizeof(cwd))) {
|
2011-11-26 04:07:38 +00:00
|
|
|
char origpath[FILE_MAX];
|
|
|
|
BLI_strncpy(origpath, path, FILE_MAX);
|
2015-10-08 15:05:58 +11:00
|
|
|
BLI_join_dirfile(path, maxlen, cwd, origpath);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
printf("Could not get the current working directory - $PWD for an unknown reason.\n");
|
2008-09-15 01:32:53 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
return wasrelative;
|
|
|
|
}
|
|
|
|
|
2015-05-06 06:05:31 +10:00
|
|
|
#ifdef _WIN32
|
|
|
|
/**
|
|
|
|
* Tries appending each of the semicolon-separated extensions in the PATHEXT
|
|
|
|
* environment variable (Windows-only) onto *name in turn until such a file is found.
|
|
|
|
* Returns success/failure.
|
|
|
|
*/
|
2015-05-06 06:34:19 +10:00
|
|
|
bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen)
|
2015-05-06 06:05:31 +10:00
|
|
|
{
|
|
|
|
bool retval = false;
|
|
|
|
int type;
|
|
|
|
|
|
|
|
type = BLI_exists(name);
|
|
|
|
if ((type == 0) || S_ISDIR(type)) {
|
2015-06-04 16:48:56 +10:00
|
|
|
/* typically 3-5, ".EXE", ".BAT"... etc */
|
|
|
|
const int ext_max = 12;
|
2015-06-02 15:38:14 +10:00
|
|
|
const char *ext = getenv("PATHEXT");
|
|
|
|
if (ext) {
|
|
|
|
const int name_len = strlen(name);
|
2015-06-04 16:48:56 +10:00
|
|
|
char *filename = alloca(name_len + ext_max);
|
|
|
|
char *filename_ext;
|
2015-06-02 15:38:14 +10:00
|
|
|
const char *ext_next;
|
2015-06-04 16:48:56 +10:00
|
|
|
|
2015-06-02 15:38:14 +10:00
|
|
|
/* null terminated in the loop */
|
|
|
|
memcpy(filename, name, name_len);
|
2015-06-04 16:48:56 +10:00
|
|
|
filename_ext = filename + name_len;
|
|
|
|
|
2015-05-06 06:05:31 +10:00
|
|
|
do {
|
2015-06-02 15:38:14 +10:00
|
|
|
int ext_len;
|
|
|
|
ext_next = strchr(ext, ';');
|
|
|
|
ext_len = ext_next ? ((ext_next++) - ext) : strlen(ext);
|
|
|
|
|
2015-06-04 16:48:56 +10:00
|
|
|
if (LIKELY(ext_len < ext_max)) {
|
|
|
|
memcpy(filename_ext, ext, ext_len);
|
|
|
|
filename_ext[ext_len] = '\0';
|
2015-05-06 06:05:31 +10:00
|
|
|
|
2015-06-06 21:02:16 +10:00
|
|
|
type = BLI_exists(filename);
|
|
|
|
if (type && (!S_ISDIR(type))) {
|
2015-06-04 16:48:56 +10:00
|
|
|
retval = true;
|
|
|
|
BLI_strncpy(name, filename, maxlen);
|
|
|
|
break;
|
|
|
|
}
|
2015-05-06 06:05:31 +10:00
|
|
|
}
|
2015-06-02 15:38:14 +10:00
|
|
|
} while ((ext = ext_next));
|
2015-05-06 06:05:31 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
retval = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
#endif /* WIN32 */
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Search for a binary (executable)
|
|
|
|
*/
|
2015-05-06 06:34:19 +10:00
|
|
|
bool BLI_path_program_search(
|
2015-05-06 06:05:31 +10:00
|
|
|
char *fullname, const size_t maxlen,
|
|
|
|
const char *name)
|
|
|
|
{
|
|
|
|
const char *path;
|
|
|
|
bool retval = false;
|
|
|
|
|
|
|
|
#ifdef _WIN32
|
|
|
|
const char separator = ';';
|
|
|
|
#else
|
|
|
|
const char separator = ':';
|
|
|
|
#endif
|
|
|
|
|
|
|
|
path = getenv("PATH");
|
|
|
|
if (path) {
|
|
|
|
char filename[FILE_MAX];
|
|
|
|
const char *temp;
|
|
|
|
|
|
|
|
do {
|
|
|
|
temp = strchr(path, separator);
|
|
|
|
if (temp) {
|
|
|
|
strncpy(filename, path, temp - path);
|
|
|
|
filename[temp - path] = 0;
|
|
|
|
path = temp + 1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
strncpy(filename, path, sizeof(filename));
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_path_append(filename, maxlen, name);
|
|
|
|
if (
|
|
|
|
#ifdef _WIN32
|
2015-05-06 06:34:19 +10:00
|
|
|
BLI_path_program_extensions_add_win32(filename, maxlen)
|
2015-05-06 06:05:31 +10:00
|
|
|
#else
|
|
|
|
BLI_exists(filename)
|
|
|
|
#endif
|
|
|
|
)
|
|
|
|
{
|
|
|
|
BLI_strncpy(fullname, filename, maxlen);
|
|
|
|
retval = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} while (temp);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (retval == false) {
|
|
|
|
*fullname = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2013-03-05 03:17:46 +00:00
|
|
|
/**
|
2013-09-23 14:48:28 +00:00
|
|
|
* Sets the specified environment variable to the specified value,
|
|
|
|
* and clears it if val == NULL.
|
2013-03-05 03:17:46 +00:00
|
|
|
*/
|
2012-05-12 15:13:06 +00:00
|
|
|
void BLI_setenv(const char *env, const char *val)
|
2009-07-21 09:26:28 +00:00
|
|
|
{
|
2011-09-21 08:40:30 +00:00
|
|
|
/* free windows */
|
2013-09-23 14:48:28 +00:00
|
|
|
|
2017-05-27 15:34:55 -04:00
|
|
|
#if (defined(WIN32) || defined(WIN64))
|
2012-03-20 02:17:37 +00:00
|
|
|
uputenv(env, val);
|
|
|
|
|
2009-07-21 09:26:28 +00:00
|
|
|
#else
|
|
|
|
/* linux/osx/bsd */
|
2013-09-23 14:48:28 +00:00
|
|
|
if (val)
|
|
|
|
setenv(env, val, 1);
|
|
|
|
else
|
|
|
|
unsetenv(env);
|
2009-07-21 09:26:28 +00:00
|
|
|
#endif
|
|
|
|
}
|
2009-04-11 02:18:24 +00:00
|
|
|
|
2009-10-19 18:44:09 +00:00
|
|
|
|
|
|
|
/**
|
2012-03-03 20:19:11 +00:00
|
|
|
* Only set an env var if already not there.
|
|
|
|
* Like Unix setenv(env, val, 0);
|
2013-03-05 03:17:46 +00:00
|
|
|
*
|
|
|
|
* (not used anywhere).
|
2009-10-19 18:44:09 +00:00
|
|
|
*/
|
2012-05-12 15:13:06 +00:00
|
|
|
void BLI_setenv_if_new(const char *env, const char *val)
|
2009-10-19 18:44:09 +00:00
|
|
|
{
|
2012-03-24 06:18:31 +00:00
|
|
|
if (getenv(env) == NULL)
|
2009-10-19 18:44:09 +00:00
|
|
|
BLI_setenv(env, val);
|
|
|
|
}
|
|
|
|
|
2013-03-05 03:17:46 +00:00
|
|
|
/**
|
2015-01-04 17:54:12 +01:00
|
|
|
* Strips off nonexistent (or non-accessible) subdirectories from the end of *dir, leaving the path of
|
|
|
|
* the lowest-level directory that does exist and we can read.
|
2013-03-05 03:17:46 +00:00
|
|
|
*/
|
2011-09-28 05:53:40 +00:00
|
|
|
void BLI_make_exist(char *dir)
|
|
|
|
{
|
2015-04-08 21:57:49 +02:00
|
|
|
bool valid_path = true;
|
2010-10-27 06:41:48 +00:00
|
|
|
|
2015-04-08 21:57:49 +02:00
|
|
|
/* Loop as long as cur path is not a dir, and we can get a parent path. */
|
|
|
|
while ((BLI_access(dir, R_OK) != 0) && (valid_path = BLI_parent_dir(dir)));
|
2010-10-27 06:41:48 +00:00
|
|
|
|
2015-04-08 21:57:49 +02:00
|
|
|
/* If we could not find an existing dir, use default root... */
|
|
|
|
if (!valid_path || !dir[0]) {
|
2010-10-27 06:41:48 +00:00
|
|
|
#ifdef WIN32
|
2015-04-08 21:57:49 +02:00
|
|
|
get_default_root(dir);
|
2002-10-12 11:37:38 +00:00
|
|
|
#else
|
2015-04-08 21:57:49 +02:00
|
|
|
strcpy(dir, "/");
|
2010-10-27 06:41:48 +00:00
|
|
|
#endif
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-03-05 03:17:46 +00:00
|
|
|
/**
|
|
|
|
* Ensures that the parent directory of *name exists.
|
2017-04-17 12:04:38 +02:00
|
|
|
*
|
|
|
|
* \return true on success (i.e. given path now exists on FS), false otherwise.
|
2013-03-05 03:17:46 +00:00
|
|
|
*/
|
2017-04-17 12:04:38 +02:00
|
|
|
bool BLI_make_existing_file(const char *name)
|
Giant commit!
A full detailed description of this will be done later... is several days
of work. Here's a summary:
Render:
- Full cleanup of render code, removing *all* globals and bad level calls
all over blender. Render module is now not called abusive anymore
- API-fied calls to rendering
- Full recode of internal render pipeline. Is now rendering tiles by
default, prepared for much smarter 'bucket' render later.
- Each thread now can render a full part
- Renders were tested with 4 threads, goes fine, apart from some lookup
tables in softshadow and AO still
- Rendering is prepared to do multiple layers and passes
- No single 32 bits trick in render code anymore, all 100% floats now.
Writing images/movies
- moved writing images to blender kernel (bye bye 'schrijfplaatje'!)
- made a new Movie handle system, also in kernel. This will enable much
easier use of movies in Blender
PreviewRender:
- Using new render API, previewrender (in buttons) now uses regular render
code to generate images.
- new datafile 'preview.blend.c' has the preview scenes in it
- previews get rendered in exact displayed size (1 pixel = 1 pixel)
3D Preview render
- new; press Pkey in 3d window, for a panel that continuously renders
(pkey is for games, i know... but we dont do that in orange now!)
- this render works nearly identical to buttons-preview render, so it stops
rendering on any event (mouse, keyboard, etc)
- on moving/scaling the panel, the render code doesn't recreate all geometry
- same for shifting/panning view
- all other operations (now) regenerate the full render database still.
- this is WIP... but big fun, especially for simple scenes!
Compositor
- Using same node system as now in use for shaders, you can composit images
- works pretty straightforward... needs much more options/tools and integration
with rendering still
- is not threaded yet, nor is so smart to only recalculate changes... will be
done soon!
- the "Render Result" node will get all layers/passes as output sockets
- The "Output" node renders to a builtin image, which you can view in the Image
window. (yes, output nodes to render-result, and to files, is on the list!)
The Bad News
- "Unified Render" is removed. It might come back in some stage, but this
system should be built from scratch. I can't really understand this code...
I expect it is not much needed, especially with advanced layer/passes
control
- Panorama render, Field render, Motion blur, is not coded yet... (I had to
recode every single feature in render, so...!)
- Lens Flare is also not back... needs total revision, might become composit
effect though (using zbuffer for visibility)
- Part render is gone! (well, thats obvious, its default now).
- The render window is only restored with limited functionality... I am going
to check first the option to render to a Image window, so Blender can become
a true single-window application. :)
For example, the 'Spare render buffer' (jkey) doesnt work.
- Render with border, now default creates a smaller image
- No zbuffers are written yet... on the todo!
- Scons files and MSVC will need work to get compiling again
OK... thats what I can quickly recall. Now go compiling!
2006-01-23 22:05:47 +00:00
|
|
|
{
|
2013-03-05 06:26:10 +00:00
|
|
|
char di[FILE_MAX];
|
|
|
|
BLI_split_dir_part(name, di, sizeof(di));
|
|
|
|
|
2014-10-29 14:11:19 +01:00
|
|
|
/* make if the dir doesn't exist */
|
2017-04-17 12:04:38 +02:00
|
|
|
return BLI_dir_create_recursive(di);
|
Giant commit!
A full detailed description of this will be done later... is several days
of work. Here's a summary:
Render:
- Full cleanup of render code, removing *all* globals and bad level calls
all over blender. Render module is now not called abusive anymore
- API-fied calls to rendering
- Full recode of internal render pipeline. Is now rendering tiles by
default, prepared for much smarter 'bucket' render later.
- Each thread now can render a full part
- Renders were tested with 4 threads, goes fine, apart from some lookup
tables in softshadow and AO still
- Rendering is prepared to do multiple layers and passes
- No single 32 bits trick in render code anymore, all 100% floats now.
Writing images/movies
- moved writing images to blender kernel (bye bye 'schrijfplaatje'!)
- made a new Movie handle system, also in kernel. This will enable much
easier use of movies in Blender
PreviewRender:
- Using new render API, previewrender (in buttons) now uses regular render
code to generate images.
- new datafile 'preview.blend.c' has the preview scenes in it
- previews get rendered in exact displayed size (1 pixel = 1 pixel)
3D Preview render
- new; press Pkey in 3d window, for a panel that continuously renders
(pkey is for games, i know... but we dont do that in orange now!)
- this render works nearly identical to buttons-preview render, so it stops
rendering on any event (mouse, keyboard, etc)
- on moving/scaling the panel, the render code doesn't recreate all geometry
- same for shifting/panning view
- all other operations (now) regenerate the full render database still.
- this is WIP... but big fun, especially for simple scenes!
Compositor
- Using same node system as now in use for shaders, you can composit images
- works pretty straightforward... needs much more options/tools and integration
with rendering still
- is not threaded yet, nor is so smart to only recalculate changes... will be
done soon!
- the "Render Result" node will get all layers/passes as output sockets
- The "Output" node renders to a builtin image, which you can view in the Image
window. (yes, output nodes to render-result, and to files, is on the list!)
The Bad News
- "Unified Render" is removed. It might come back in some stage, but this
system should be built from scratch. I can't really understand this code...
I expect it is not much needed, especially with advanced layer/passes
control
- Panorama render, Field render, Motion blur, is not coded yet... (I had to
recode every single feature in render, so...!)
- Lens Flare is also not back... needs total revision, might become composit
effect though (using zbuffer for visibility)
- Part render is gone! (well, thats obvious, its default now).
- The render window is only restored with limited functionality... I am going
to check first the option to render to a Image window, so Blender can become
a true single-window application. :)
For example, the 'Spare render buffer' (jkey) doesnt work.
- Render with border, now default creates a smaller image
- No zbuffers are written yet... on the todo!
- Scons files and MSVC will need work to get compiling again
OK... thats what I can quickly recall. Now go compiling!
2006-01-23 22:05:47 +00:00
|
|
|
}
|
|
|
|
|
2013-03-05 03:17:46 +00:00
|
|
|
/**
|
|
|
|
* Returns in *string the concatenation of *dir and *file (also with *relabase on the
|
|
|
|
* front if specified and *dir begins with "//"). Normalizes all occurrences of path
|
|
|
|
* separators, including ensuring there is exactly one between the copies of *dir and *file,
|
|
|
|
* and between the copies of *relabase and *dir.
|
|
|
|
*
|
|
|
|
* \param relabase Optional prefix to substitute for "//" on front of *dir
|
|
|
|
* \param string Area to return result
|
|
|
|
*/
|
|
|
|
void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2006-02-11 15:02:23 +00:00
|
|
|
int sl;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2011-10-23 05:56:55 +00:00
|
|
|
if (string) {
|
|
|
|
/* ensure this is always set even if dir/file are NULL */
|
2012-05-12 15:13:06 +00:00
|
|
|
string[0] = '\0';
|
2011-10-23 05:56:55 +00:00
|
|
|
|
|
|
|
if (ELEM(NULL, dir, file)) {
|
|
|
|
return; /* We don't want any NULLs */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return; /* string is NULL, probably shouldnt happen but return anyway */
|
|
|
|
}
|
|
|
|
|
2005-06-10 13:12:59 +00:00
|
|
|
|
2005-05-20 12:18:11 +00:00
|
|
|
/* we first push all slashes into unix mode, just to make sure we don't get
|
2012-03-03 20:19:11 +00:00
|
|
|
* any mess with slashes later on. -jesterKing */
|
2005-11-05 13:09:43 +00:00
|
|
|
/* constant strings can be passed for those parameters - don't change them - elubie */
|
2012-03-03 20:19:11 +00:00
|
|
|
#if 0
|
2015-06-30 15:18:03 +10:00
|
|
|
BLI_str_replace_char(relabase, '\\', '/');
|
|
|
|
BLI_str_replace_char(dir, '\\', '/');
|
|
|
|
BLI_str_replace_char(file, '\\', '/');
|
2012-03-03 20:19:11 +00:00
|
|
|
#endif
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2012-10-21 05:46:41 +00:00
|
|
|
/* Resolve relative references */
|
2002-10-12 11:37:38 +00:00
|
|
|
if (relabase && dir[0] == '/' && dir[1] == '/') {
|
|
|
|
char *lslash;
|
|
|
|
|
|
|
|
/* Get the file name, chop everything past the last slash (ie. the filename) */
|
|
|
|
strcpy(string, relabase);
|
|
|
|
|
2013-03-04 19:27:51 +00:00
|
|
|
lslash = (char *)BLI_last_slash(string);
|
2012-05-12 15:13:06 +00:00
|
|
|
if (lslash) *(lslash + 1) = 0;
|
2002-10-12 11:37:38 +00:00
|
|
|
|
2012-05-12 15:13:06 +00:00
|
|
|
dir += 2; /* Skip over the relative reference */
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
2006-08-20 14:41:13 +00:00
|
|
|
#ifdef WIN32
|
|
|
|
else {
|
2012-05-12 15:13:06 +00:00
|
|
|
if (BLI_strnlen(dir, 3) >= 2 && dir[1] == ':') {
|
2006-08-20 14:41:13 +00:00
|
|
|
BLI_strncpy(string, dir, 3);
|
|
|
|
dir += 2;
|
|
|
|
}
|
2014-04-21 16:49:35 +02:00
|
|
|
else if (BLI_strnlen(dir, 3) >= 2 && BLI_path_is_unc(dir)) {
|
|
|
|
string[0] = 0;
|
|
|
|
}
|
2006-08-20 14:41:13 +00:00
|
|
|
else { /* no drive specified */
|
2012-05-12 15:13:06 +00:00
|
|
|
/* first option: get the drive from the relabase if it has one */
|
2014-04-21 16:49:35 +02:00
|
|
|
if (relabase && BLI_strnlen(relabase, 3) >= 2 && relabase[1] == ':') {
|
2012-10-21 05:46:41 +00:00
|
|
|
BLI_strncpy(string, relabase, 3);
|
2006-08-20 14:41:13 +00:00
|
|
|
string[2] = '\\';
|
|
|
|
string[3] = '\0';
|
|
|
|
}
|
|
|
|
else { /* we're out of luck here, guessing the first valid drive, usually c:\ */
|
|
|
|
get_default_root(string);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ignore leading slashes */
|
|
|
|
while (*dir == '/' || *dir == '\\') dir++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2002-10-12 11:37:38 +00:00
|
|
|
strcat(string, dir);
|
|
|
|
|
2012-10-21 05:46:41 +00:00
|
|
|
/* Make sure string ends in one (and only one) slash */
|
2006-02-11 15:02:23 +00:00
|
|
|
/* first trim all slashes from the end of the string */
|
|
|
|
sl = strlen(string);
|
2012-05-12 15:13:06 +00:00
|
|
|
while (sl > 0 && (string[sl - 1] == '/' || string[sl - 1] == '\\') ) {
|
|
|
|
string[sl - 1] = '\0';
|
2006-02-11 15:02:23 +00:00
|
|
|
sl--;
|
|
|
|
}
|
|
|
|
/* since we've now removed all slashes, put back one slash at the end. */
|
|
|
|
strcat(string, "/");
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */
|
|
|
|
file++;
|
|
|
|
|
2012-05-12 15:13:06 +00:00
|
|
|
strcat(string, file);
|
2002-10-12 11:37:38 +00:00
|
|
|
|
|
|
|
/* Push all slashes to the system preferred direction */
|
2014-07-31 01:40:05 +10:00
|
|
|
BLI_path_native_slash(string);
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
2014-01-31 03:09:01 +11:00
|
|
|
static bool testextensie_ex(const char *str, const size_t str_len,
|
|
|
|
const char *ext, const size_t ext_len)
|
|
|
|
{
|
|
|
|
BLI_assert(strlen(str) == str_len);
|
|
|
|
BLI_assert(strlen(ext) == ext_len);
|
|
|
|
|
|
|
|
return (((str_len == 0 || ext_len == 0 || ext_len >= str_len) == 0) &&
|
|
|
|
(BLI_strcasecmp(ext, str + str_len - ext_len) == 0));
|
|
|
|
}
|
|
|
|
|
2013-03-04 18:36:37 +00:00
|
|
|
/* does str end with ext. */
|
|
|
|
bool BLI_testextensie(const char *str, const char *ext)
|
2002-10-12 11:37:38 +00:00
|
|
|
{
|
2014-01-31 03:09:01 +11:00
|
|
|
return testextensie_ex(str, strlen(str), ext, strlen(ext));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BLI_testextensie_n(const char *str, ...)
|
|
|
|
{
|
|
|
|
const size_t str_len = strlen(str);
|
|
|
|
|
|
|
|
va_list args;
|
|
|
|
const char *ext;
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
va_start(args, str);
|
|
|
|
|
|
|
|
while ((ext = (const char *) va_arg(args, void *))) {
|
|
|
|
if (testextensie_ex(str, str_len, ext, strlen(ext))) {
|
|
|
|
ret = true;
|
2014-12-01 14:33:38 +01:00
|
|
|
break;
|
2014-01-31 03:09:01 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
return ret;
|
2002-10-12 11:37:38 +00:00
|
|
|
}
|
|
|
|
|
2013-03-04 18:36:37 +00:00
|
|
|
/* does str end with any of the suffixes in *ext_array. */
|
|
|
|
bool BLI_testextensie_array(const char *str, const char **ext_array)
|
2010-08-03 12:34:42 +00:00
|
|
|
{
|
2014-01-31 03:09:01 +11:00
|
|
|
const size_t str_len = strlen(str);
|
2012-05-12 15:13:06 +00:00
|
|
|
int i = 0;
|
2014-01-31 03:09:01 +11:00
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
while (ext_array[i]) {
|
2014-01-31 03:09:01 +11:00
|
|
|
if (testextensie_ex(str, str_len, ext_array[i], strlen(ext_array[i]))) {
|
2013-03-04 18:36:37 +00:00
|
|
|
return true;
|
2010-08-03 12:34:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
2013-03-04 18:36:37 +00:00
|
|
|
return false;
|
2010-08-03 12:34:42 +00:00
|
|
|
}
|
|
|
|
|
2013-03-05 03:17:46 +00:00
|
|
|
/**
|
|
|
|
* Semicolon separated wildcards, eg:
|
|
|
|
* '*.zip;*.py;*.exe'
|
|
|
|
* does str match any of the semicolon-separated glob patterns in fnmatch.
|
|
|
|
*/
|
2013-03-04 18:36:37 +00:00
|
|
|
bool BLI_testextensie_glob(const char *str, const char *ext_fnmatch)
|
2010-09-24 06:20:43 +00:00
|
|
|
{
|
2012-05-12 15:13:06 +00:00
|
|
|
const char *ext_step = ext_fnmatch;
|
2010-09-24 06:20:43 +00:00
|
|
|
char pattern[16];
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
while (ext_step[0]) {
|
2014-04-27 00:20:55 +10:00
|
|
|
const char *ext_next;
|
2015-09-07 19:21:12 +02:00
|
|
|
size_t len_ext;
|
2010-09-24 06:20:43 +00:00
|
|
|
|
2012-05-12 15:13:06 +00:00
|
|
|
if ((ext_next = strchr(ext_step, ';'))) {
|
2015-09-07 19:21:12 +02:00
|
|
|
len_ext = ext_next - ext_step + 1;
|
2015-09-09 11:02:32 +02:00
|
|
|
BLI_strncpy(pattern, ext_step, (len_ext > sizeof(pattern)) ? sizeof(pattern) : len_ext);
|
2010-09-24 06:20:43 +00:00
|
|
|
}
|
|
|
|
else {
|
2015-09-09 11:02:32 +02:00
|
|
|
len_ext = BLI_strncpy_rlen(pattern, ext_step, sizeof(pattern));
|
2010-09-24 06:20:43 +00:00
|
|
|
}
|
|
|
|
|
2012-05-12 15:13:06 +00:00
|
|
|
if (fnmatch(pattern, str, FNM_CASEFOLD) == 0) {
|
2013-03-04 18:36:37 +00:00
|
|
|
return true;
|
2010-09-24 06:20:43 +00:00
|
|
|
}
|
|
|
|
ext_step += len_ext;
|
|
|
|
}
|
|
|
|
|
2013-03-04 18:36:37 +00:00
|
|
|
return false;
|
2010-09-24 06:20:43 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-03-05 03:17:46 +00:00
|
|
|
/**
|
|
|
|
* Removes any existing extension on the end of \a path and appends \a ext.
|
|
|
|
* \return false if there was no room.
|
|
|
|
*/
|
|
|
|
bool BLI_replace_extension(char *path, size_t maxlen, const char *ext)
|
Merge image related changes from the render branch. This includes the image
tile cache code in imbuf, but it is not hooked up to the render engine.
Imbuf module: some small refactoring and removing a lot of unused or old code
(about 6.5k lines).
* Added a ImFileType struct with callbacks to make adding an file format type,
or making changes to the API easier.
* Move imbuf init/exit code into IMB_init()/IMB_exit() functions.
* Increased mipmap levels from 10 to 20, you run into this limit already with
a 2k image.
* Removed hamx, amiga, anim5 format support.
* Removed colormap saving, only simple colormap code now for reading tga.
* Removed gen_dynlibtiff.py, editing this is almost as much work as just
editing the code directly.
* Functions removed that were only used for sequencer plugin API:
IMB_anim_nextpic, IMB_clever_double, IMB_antialias, IMB_gamwarp,
IMB_scalefieldImBuf, IMB_scalefastfieldImBuf, IMB_onethird, IMB_halflace,
IMB_dit0, IMB_dit2, IMB_cspace
* Write metadata info into OpenEXR images. Can be viewed with the command
line utility 'exrheader'
For the image tile cache code, see this page:
http://wiki.blender.org/index.php/Dev:2.5/Source/Imaging/ImageTileCache
2010-05-07 15:18:04 +00:00
|
|
|
{
|
2013-03-05 03:17:46 +00:00
|
|
|
const size_t path_len = strlen(path);
|
|
|
|
const size_t ext_len = strlen(ext);
|
2011-12-21 20:56:49 +00:00
|
|
|
ssize_t a;
|
Merge image related changes from the render branch. This includes the image
tile cache code in imbuf, but it is not hooked up to the render engine.
Imbuf module: some small refactoring and removing a lot of unused or old code
(about 6.5k lines).
* Added a ImFileType struct with callbacks to make adding an file format type,
or making changes to the API easier.
* Move imbuf init/exit code into IMB_init()/IMB_exit() functions.
* Increased mipmap levels from 10 to 20, you run into this limit already with
a 2k image.
* Removed hamx, amiga, anim5 format support.
* Removed colormap saving, only simple colormap code now for reading tga.
* Removed gen_dynlibtiff.py, editing this is almost as much work as just
editing the code directly.
* Functions removed that were only used for sequencer plugin API:
IMB_anim_nextpic, IMB_clever_double, IMB_antialias, IMB_gamwarp,
IMB_scalefieldImBuf, IMB_scalefastfieldImBuf, IMB_onethird, IMB_halflace,
IMB_dit0, IMB_dit2, IMB_cspace
* Write metadata info into OpenEXR images. Can be viewed with the command
line utility 'exrheader'
For the image tile cache code, see this page:
http://wiki.blender.org/index.php/Dev:2.5/Source/Imaging/ImageTileCache
2010-05-07 15:18:04 +00:00
|
|
|
|
2012-05-12 15:13:06 +00:00
|
|
|
for (a = path_len - 1; a >= 0; a--) {
|
2014-07-20 01:30:29 +10:00
|
|
|
if (ELEM(path[a], '.', '/', '\\')) {
|
Merge image related changes from the render branch. This includes the image
tile cache code in imbuf, but it is not hooked up to the render engine.
Imbuf module: some small refactoring and removing a lot of unused or old code
(about 6.5k lines).
* Added a ImFileType struct with callbacks to make adding an file format type,
or making changes to the API easier.
* Move imbuf init/exit code into IMB_init()/IMB_exit() functions.
* Increased mipmap levels from 10 to 20, you run into this limit already with
a 2k image.
* Removed hamx, amiga, anim5 format support.
* Removed colormap saving, only simple colormap code now for reading tga.
* Removed gen_dynlibtiff.py, editing this is almost as much work as just
editing the code directly.
* Functions removed that were only used for sequencer plugin API:
IMB_anim_nextpic, IMB_clever_double, IMB_antialias, IMB_gamwarp,
IMB_scalefieldImBuf, IMB_scalefastfieldImBuf, IMB_onethird, IMB_halflace,
IMB_dit0, IMB_dit2, IMB_cspace
* Write metadata info into OpenEXR images. Can be viewed with the command
line utility 'exrheader'
For the image tile cache code, see this page:
http://wiki.blender.org/index.php/Dev:2.5/Source/Imaging/ImageTileCache
2010-05-07 15:18:04 +00:00
|
|
|
break;
|
2011-03-08 08:33:52 +00:00
|
|
|
}
|
|
|
|
}
|
Merge image related changes from the render branch. This includes the image
tile cache code in imbuf, but it is not hooked up to the render engine.
Imbuf module: some small refactoring and removing a lot of unused or old code
(about 6.5k lines).
* Added a ImFileType struct with callbacks to make adding an file format type,
or making changes to the API easier.
* Move imbuf init/exit code into IMB_init()/IMB_exit() functions.
* Increased mipmap levels from 10 to 20, you run into this limit already with
a 2k image.
* Removed hamx, amiga, anim5 format support.
* Removed colormap saving, only simple colormap code now for reading tga.
* Removed gen_dynlibtiff.py, editing this is almost as much work as just
editing the code directly.
* Functions removed that were only used for sequencer plugin API:
IMB_anim_nextpic, IMB_clever_double, IMB_antialias, IMB_gamwarp,
IMB_scalefieldImBuf, IMB_scalefastfieldImBuf, IMB_onethird, IMB_halflace,
IMB_dit0, IMB_dit2, IMB_cspace
* Write metadata info into OpenEXR images. Can be viewed with the command
line utility 'exrheader'
For the image tile cache code, see this page:
http://wiki.blender.org/index.php/Dev:2.5/Source/Imaging/ImageTileCache
2010-05-07 15:18:04 +00:00
|
|
|
|
2011-12-21 20:56:49 +00:00
|
|
|
if ((a < 0) || (path[a] != '.')) {
|
2012-05-12 15:13:06 +00:00
|
|
|
a = path_len;
|
2011-11-15 07:35:28 +00:00
|
|
|
}
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (a + ext_len >= maxlen)
|
2013-03-05 03:17:46 +00:00
|
|
|
return false;
|
2011-10-31 00:23:42 +00:00
|
|
|
|
2012-05-12 15:13:06 +00:00
|
|
|
memcpy(path + a, ext, ext_len + 1);
|
2013-03-05 03:17:46 +00:00
|
|
|
return true;
|
2011-10-31 00:23:42 +00:00
|
|
|
}
|
|
|
|
|
2013-03-05 03:17:46 +00:00
|
|
|
/**
|
|
|
|
* Strip's trailing '.'s and adds the extension only when needed
|
|
|
|
*/
|
|
|
|
bool BLI_ensure_extension(char *path, size_t maxlen, const char *ext)
|
2011-10-31 00:23:42 +00:00
|
|
|
{
|
2013-03-05 03:17:46 +00:00
|
|
|
const size_t path_len = strlen(path);
|
|
|
|
const size_t ext_len = strlen(ext);
|
2011-12-21 20:56:49 +00:00
|
|
|
ssize_t a;
|
2011-10-31 00:23:42 +00:00
|
|
|
|
2013-03-05 03:17:46 +00:00
|
|
|
/* first check the extension is already there */
|
2015-01-26 16:03:11 +01:00
|
|
|
if ((ext_len <= path_len) && (STREQ(path + (path_len - ext_len), ext))) {
|
2013-03-05 03:17:46 +00:00
|
|
|
return true;
|
2011-10-31 00:23:42 +00:00
|
|
|
}
|
|
|
|
|
2012-05-12 15:13:06 +00:00
|
|
|
for (a = path_len - 1; a >= 0; a--) {
|
2011-10-31 00:23:42 +00:00
|
|
|
if (path[a] == '.') {
|
2012-05-12 15:13:06 +00:00
|
|
|
path[a] = '\0';
|
2011-10-31 00:23:42 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
a++;
|
|
|
|
|
2012-03-24 06:18:31 +00:00
|
|
|
if (a + ext_len >= maxlen)
|
2013-03-05 03:17:46 +00:00
|
|
|
return false;
|
Merge image related changes from the render branch. This includes the image
tile cache code in imbuf, but it is not hooked up to the render engine.
Imbuf module: some small refactoring and removing a lot of unused or old code
(about 6.5k lines).
* Added a ImFileType struct with callbacks to make adding an file format type,
or making changes to the API easier.
* Move imbuf init/exit code into IMB_init()/IMB_exit() functions.
* Increased mipmap levels from 10 to 20, you run into this limit already with
a 2k image.
* Removed hamx, amiga, anim5 format support.
* Removed colormap saving, only simple colormap code now for reading tga.
* Removed gen_dynlibtiff.py, editing this is almost as much work as just
editing the code directly.
* Functions removed that were only used for sequencer plugin API:
IMB_anim_nextpic, IMB_clever_double, IMB_antialias, IMB_gamwarp,
IMB_scalefieldImBuf, IMB_scalefastfieldImBuf, IMB_onethird, IMB_halflace,
IMB_dit0, IMB_dit2, IMB_cspace
* Write metadata info into OpenEXR images. Can be viewed with the command
line utility 'exrheader'
For the image tile cache code, see this page:
http://wiki.blender.org/index.php/Dev:2.5/Source/Imaging/ImageTileCache
2010-05-07 15:18:04 +00:00
|
|
|
|
2012-05-12 15:13:06 +00:00
|
|
|
memcpy(path + a, ext, ext_len + 1);
|
2013-03-05 03:17:46 +00:00
|
|
|
return true;
|
Merge image related changes from the render branch. This includes the image
tile cache code in imbuf, but it is not hooked up to the render engine.
Imbuf module: some small refactoring and removing a lot of unused or old code
(about 6.5k lines).
* Added a ImFileType struct with callbacks to make adding an file format type,
or making changes to the API easier.
* Move imbuf init/exit code into IMB_init()/IMB_exit() functions.
* Increased mipmap levels from 10 to 20, you run into this limit already with
a 2k image.
* Removed hamx, amiga, anim5 format support.
* Removed colormap saving, only simple colormap code now for reading tga.
* Removed gen_dynlibtiff.py, editing this is almost as much work as just
editing the code directly.
* Functions removed that were only used for sequencer plugin API:
IMB_anim_nextpic, IMB_clever_double, IMB_antialias, IMB_gamwarp,
IMB_scalefieldImBuf, IMB_scalefastfieldImBuf, IMB_onethird, IMB_halflace,
IMB_dit0, IMB_dit2, IMB_cspace
* Write metadata info into OpenEXR images. Can be viewed with the command
line utility 'exrheader'
For the image tile cache code, see this page:
http://wiki.blender.org/index.php/Dev:2.5/Source/Imaging/ImageTileCache
2010-05-07 15:18:04 +00:00
|
|
|
}
|
|
|
|
|
2013-08-29 05:34:58 +00:00
|
|
|
bool BLI_ensure_filename(char *filepath, size_t maxlen, const char *filename)
|
|
|
|
{
|
|
|
|
char *c = (char *)BLI_last_slash(filepath);
|
|
|
|
if (!c || ((c - filepath) < maxlen - (strlen(filename) + 1))) {
|
|
|
|
strcpy(c ? &c[1] : filepath, filename);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-04-23 23:01:50 +00:00
|
|
|
/* Converts "/foo/bar.txt" to "/foo/" and "bar.txt"
|
2008-04-26 13:08:57 +00:00
|
|
|
* - wont change 'string'
|
|
|
|
* - wont create any directories
|
|
|
|
* - dosnt use CWD, or deal with relative paths.
|
|
|
|
* - Only fill's in *dir and *file when they are non NULL
|
|
|
|
* */
|
2011-10-15 03:56:05 +00:00
|
|
|
void BLI_split_dirfile(const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen)
|
2008-04-26 13:08:57 +00:00
|
|
|
{
|
2013-03-04 19:27:51 +00:00
|
|
|
const char *lslash_str = BLI_last_slash(string);
|
2013-03-05 03:17:46 +00:00
|
|
|
const size_t lslash = lslash_str ? (size_t)(lslash_str - string) + 1 : 0;
|
2010-04-23 23:01:50 +00:00
|
|
|
|
2008-04-26 13:08:57 +00:00
|
|
|
if (dir) {
|
|
|
|
if (lslash) {
|
2012-03-11 19:09:01 +00:00
|
|
|
BLI_strncpy(dir, string, MIN2(dirlen, lslash + 1)); /* +1 to include the slash and the last char */
|
2011-10-15 03:56:05 +00:00
|
|
|
}
|
|
|
|
else {
|
2008-04-26 13:08:57 +00:00
|
|
|
dir[0] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (file) {
|
2012-05-12 15:13:06 +00:00
|
|
|
BLI_strncpy(file, string + lslash, filelen);
|
2008-04-26 13:08:57 +00:00
|
|
|
}
|
|
|
|
}
|
2005-03-28 15:29:59 +00:00
|
|
|
|
2013-03-05 03:17:46 +00:00
|
|
|
/**
|
|
|
|
* Copies the parent directory part of string into *dir, max length dirlen.
|
|
|
|
*/
|
2011-10-21 02:13:36 +00:00
|
|
|
void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen)
|
|
|
|
{
|
|
|
|
BLI_split_dirfile(string, dir, NULL, dirlen, 0);
|
|
|
|
}
|
|
|
|
|
2013-03-05 03:17:46 +00:00
|
|
|
/**
|
|
|
|
* Copies the leaf filename part of string into *file, max length filelen.
|
|
|
|
*/
|
2011-10-21 02:13:36 +00:00
|
|
|
void BLI_split_file_part(const char *string, char *file, const size_t filelen)
|
|
|
|
{
|
|
|
|
BLI_split_dirfile(string, NULL, file, 0, filelen);
|
|
|
|
}
|
|
|
|
|
2013-07-24 21:25:06 +00:00
|
|
|
/**
|
|
|
|
* Append a filename to a dir, ensuring slash separates.
|
|
|
|
*/
|
2013-09-02 11:19:21 +00:00
|
|
|
void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file)
|
2013-07-24 21:25:06 +00:00
|
|
|
{
|
|
|
|
size_t dirlen = BLI_strnlen(dst, maxlen);
|
|
|
|
|
|
|
|
/* inline BLI_add_slash */
|
|
|
|
if ((dirlen > 0) && (dst[dirlen - 1] != SEP)) {
|
|
|
|
dst[dirlen++] = SEP;
|
|
|
|
dst[dirlen] = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dirlen >= maxlen) {
|
|
|
|
return; /* fills the path */
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_strncpy(dst + dirlen, file, maxlen - dirlen);
|
|
|
|
}
|
|
|
|
|
2013-03-05 03:17:46 +00:00
|
|
|
/**
|
|
|
|
* Simple appending of filename to dir, does not check for valid path!
|
|
|
|
* Puts result into *dst, which may be same area as *dir.
|
|
|
|
*/
|
2013-09-02 11:19:21 +00:00
|
|
|
void BLI_join_dirfile(char *__restrict dst, const size_t maxlen, const char *__restrict dir, const char *__restrict file)
|
2007-02-28 21:37:14 +00:00
|
|
|
{
|
2012-05-12 15:13:06 +00:00
|
|
|
size_t dirlen = BLI_strnlen(dir, maxlen);
|
2011-10-11 05:21:24 +00:00
|
|
|
|
2013-07-24 21:25:06 +00:00
|
|
|
/* args can't match */
|
|
|
|
BLI_assert(!ELEM(dst, dir, file));
|
|
|
|
|
|
|
|
if (dirlen == maxlen) {
|
|
|
|
memcpy(dst, dir, dirlen);
|
|
|
|
dst[dirlen - 1] = '\0';
|
|
|
|
return; /* dir fills the path */
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
memcpy(dst, dir, dirlen + 1);
|
2011-10-12 11:18:46 +00:00
|
|
|
}
|
2010-07-04 15:35:23 +00:00
|
|
|
|
2011-10-12 11:18:46 +00:00
|
|
|
if (dirlen + 1 >= maxlen) {
|
|
|
|
return; /* fills the path */
|
|
|
|
}
|
2011-10-11 05:21:24 +00:00
|
|
|
|
2011-10-12 11:18:46 +00:00
|
|
|
/* inline BLI_add_slash */
|
2015-11-27 21:12:42 +01:00
|
|
|
if ((dirlen > 0) && !ELEM(dst[dirlen - 1], SEP, ALTSEP)) {
|
2012-03-12 06:53:47 +00:00
|
|
|
dst[dirlen++] = SEP;
|
2012-05-12 15:13:06 +00:00
|
|
|
dst[dirlen] = '\0';
|
2007-02-28 21:37:14 +00:00
|
|
|
}
|
2011-10-12 11:18:46 +00:00
|
|
|
|
|
|
|
if (dirlen >= maxlen) {
|
|
|
|
return; /* fills the path */
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_strncpy(dst + dirlen, file, maxlen - dirlen);
|
2007-02-28 21:37:14 +00:00
|
|
|
}
|
|
|
|
|
2017-03-24 17:29:48 +11:00
|
|
|
/**
|
|
|
|
* Join multiple strings into a path, ensuring only a single path separator between each,
|
|
|
|
* and trailing slash is kept.
|
|
|
|
*
|
|
|
|
* \note If you want a trailing slash, add ``SEP_STR`` as the last path argument,
|
|
|
|
* duplicate slashes will be cleaned up.
|
|
|
|
*/
|
|
|
|
size_t BLI_path_join(char *__restrict dst, const size_t dst_len, const char *path, ...)
|
|
|
|
{
|
|
|
|
if (UNLIKELY(dst_len == 0)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
const size_t dst_last = dst_len - 1;
|
|
|
|
size_t ofs = BLI_strncpy_rlen(dst, path, dst_len);
|
|
|
|
|
|
|
|
if (ofs == dst_last) {
|
|
|
|
return ofs;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* remove trailing slashes, unless there are _only_ trailing slashes
|
|
|
|
* (allow "//" as the first argument). */
|
|
|
|
bool has_trailing_slash = false;
|
|
|
|
if (ofs != 0) {
|
|
|
|
size_t len = ofs;
|
|
|
|
while ((len != 0) && ELEM(path[len - 1], SEP, ALTSEP)) {
|
|
|
|
len -= 1;
|
|
|
|
}
|
|
|
|
if (len != 0) {
|
|
|
|
ofs = len;
|
|
|
|
}
|
|
|
|
has_trailing_slash = (path[len] != '\0');
|
|
|
|
}
|
|
|
|
|
|
|
|
va_list args;
|
|
|
|
va_start(args, path);
|
|
|
|
while ((path = (const char *) va_arg(args, const char *))) {
|
|
|
|
has_trailing_slash = false;
|
|
|
|
const char *path_init = path;
|
|
|
|
while (ELEM(path[0], SEP, ALTSEP)) {
|
|
|
|
path++;
|
|
|
|
}
|
|
|
|
size_t len = strlen(path);
|
|
|
|
if (len != 0) {
|
|
|
|
while ((len != 0) && ELEM(path[len - 1], SEP, ALTSEP)) {
|
|
|
|
len -= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len != 0) {
|
|
|
|
/* the very first path may have a slash at the end */
|
|
|
|
if (ofs && !ELEM(dst[ofs - 1], SEP, ALTSEP)) {
|
|
|
|
dst[ofs++] = SEP;
|
|
|
|
if (ofs == dst_last) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
has_trailing_slash = (path[len] != '\0');
|
|
|
|
if (ofs + len >= dst_last) {
|
|
|
|
len = dst_last - ofs;
|
|
|
|
}
|
|
|
|
memcpy(&dst[ofs], path, len);
|
|
|
|
ofs += len;
|
|
|
|
if (ofs == dst_last) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
has_trailing_slash = (path_init != path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
if (has_trailing_slash) {
|
|
|
|
if ((ofs != dst_last) && (ofs != 0) && (ELEM(dst[ofs - 1], SEP, ALTSEP) == 0)) {
|
|
|
|
dst[ofs++] = SEP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
BLI_assert(ofs <= dst_last);
|
|
|
|
dst[ofs] = '\0';
|
|
|
|
|
|
|
|
return ofs;
|
|
|
|
}
|
|
|
|
|
2013-03-05 03:17:46 +00:00
|
|
|
/**
|
|
|
|
* like pythons os.path.basename()
|
|
|
|
*
|
|
|
|
* \return The pointer into \a path string immediately after last slash,
|
|
|
|
* or start of \a path if none found.
|
|
|
|
*/
|
2013-03-04 19:27:51 +00:00
|
|
|
const char *BLI_path_basename(const char *path)
|
2010-06-05 21:19:59 +00:00
|
|
|
{
|
2013-03-04 19:27:51 +00:00
|
|
|
const char * const filename = BLI_last_slash(path);
|
2010-06-05 21:19:59 +00:00
|
|
|
return filename ? filename + 1 : path;
|
|
|
|
}
|
2010-02-26 11:50:59 +00:00
|
|
|
|
2017-03-22 19:31:34 +11:00
|
|
|
/**
|
|
|
|
* Get an element of the path at an index, eg:
|
|
|
|
* "/some/path/file.txt" where an index of...
|
|
|
|
* - 0 or -3: "some"
|
|
|
|
* - 1 or -2: "path"
|
|
|
|
* - 2 or -1: "file.txt"
|
|
|
|
*
|
|
|
|
* Ignores multiple slashes at any point in the path (including start/end).
|
|
|
|
*/
|
|
|
|
bool BLI_path_name_at_index(const char *path, const int index, int *r_offset, int *r_len)
|
|
|
|
{
|
|
|
|
if (index >= 0) {
|
|
|
|
int index_step = 0;
|
|
|
|
int prev = -1;
|
|
|
|
int i = 0;
|
|
|
|
while (true) {
|
|
|
|
const char c = path[i];
|
|
|
|
if (ELEM(c, SEP, ALTSEP, '\0')) {
|
|
|
|
if (prev + 1 != i) {
|
|
|
|
prev += 1;
|
|
|
|
if (index_step == index) {
|
|
|
|
*r_offset = prev;
|
|
|
|
*r_len = i - prev;
|
|
|
|
/* printf("!!! %d %d\n", start, end); */
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
index_step += 1;
|
|
|
|
}
|
|
|
|
if (c == '\0') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
prev = i;
|
|
|
|
}
|
|
|
|
i += 1;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
/* negative number, reverse where -1 is the last element */
|
|
|
|
int index_step = -1;
|
|
|
|
int prev = strlen(path);
|
|
|
|
int i = prev - 1;
|
|
|
|
while (true) {
|
|
|
|
const char c = i >= 0 ? path[i] : '\0';
|
|
|
|
if (ELEM(c, SEP, ALTSEP, '\0')) {
|
|
|
|
if (prev - 1 != i) {
|
|
|
|
i += 1;
|
|
|
|
if (index_step == index) {
|
|
|
|
*r_offset = i;
|
|
|
|
*r_len = prev - i;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
index_step -= 1;
|
|
|
|
}
|
|
|
|
if (c == '\0') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
prev = i;
|
|
|
|
}
|
|
|
|
i -= 1;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-19 00:00:59 +10:00
|
|
|
/* UNUSED */
|
|
|
|
#if 0
|
2012-03-03 20:19:11 +00:00
|
|
|
/**
|
|
|
|
* Produce image export path.
|
2018-06-01 18:19:39 +02:00
|
|
|
*
|
2012-06-22 15:38:49 +00:00
|
|
|
* Returns:
|
|
|
|
* 0 if image filename is empty or if destination path
|
|
|
|
* matches image path (i.e. both are the same file).
|
|
|
|
* 2 if source is identical to destination.
|
2012-07-16 23:23:33 +00:00
|
|
|
* 1 if rebase was successful
|
2012-06-22 15:38:49 +00:00
|
|
|
* -------------------------------------------------------------
|
|
|
|
* Hint: Trailing slash in dest_dir is optional.
|
2012-03-03 20:19:11 +00:00
|
|
|
*
|
|
|
|
* Logic:
|
|
|
|
*
|
2012-06-22 15:38:49 +00:00
|
|
|
* - if an image is "below" current .blend file directory:
|
|
|
|
* rebuild the same dir structure in dest_dir
|
2012-03-03 20:19:11 +00:00
|
|
|
*
|
2018-06-01 18:19:39 +02:00
|
|
|
* Example:
|
2012-06-22 15:38:49 +00:00
|
|
|
* src : //textures/foo/bar.png
|
|
|
|
* dest: [dest_dir]/textures/foo/bar.png.
|
2012-03-03 20:19:11 +00:00
|
|
|
*
|
|
|
|
* - if an image is not "below" current .blend file directory,
|
2018-06-01 18:19:39 +02:00
|
|
|
* disregard it's path and copy it into the destination
|
2012-06-22 15:38:49 +00:00
|
|
|
* directory.
|
2012-03-03 20:19:11 +00:00
|
|
|
*
|
2012-06-22 15:38:49 +00:00
|
|
|
* Example:
|
|
|
|
* src : //../foo/bar.png becomes
|
|
|
|
* dest: [dest_dir]/bar.png.
|
2012-03-03 20:19:11 +00:00
|
|
|
*
|
2012-06-22 15:38:49 +00:00
|
|
|
* This logic ensures that all image paths are relative and
|
2012-03-03 20:19:11 +00:00
|
|
|
* that a user gets his images in one place. It'll also provide
|
|
|
|
* consistent behavior across exporters.
|
2012-06-22 15:38:49 +00:00
|
|
|
* IMPORTANT NOTE: If base_dir contains an empty string, then
|
|
|
|
* this function returns wrong results!
|
|
|
|
* XXX: test on empty base_dir and return an error ?
|
2010-02-26 11:50:59 +00:00
|
|
|
*/
|
2013-03-05 03:17:46 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
*
|
|
|
|
* \param abs Optional string to return new full path
|
|
|
|
* \param abs_len Size of *abs string
|
|
|
|
* \param rel Optional area to return new path relative to parent directory of .blend file
|
|
|
|
* (only meaningful if item is in a subdirectory thereof)
|
|
|
|
* \param rel_len Size of *rel area
|
|
|
|
* \param base_dir Path of .blend file
|
|
|
|
* \param src_dir Original path of item (any initial "//" will be expanded to
|
|
|
|
* parent directory of .blend file)
|
|
|
|
* \param dest_dir New directory into which item will be moved
|
|
|
|
* \return bli_rebase_state
|
|
|
|
*
|
|
|
|
* \note Not actually used anywhere!
|
|
|
|
*/
|
|
|
|
int BLI_rebase_path(char *abs, size_t abs_len,
|
|
|
|
char *rel, size_t rel_len,
|
|
|
|
const char *base_dir, const char *src_dir, const char *dest_dir)
|
2010-02-26 11:50:59 +00:00
|
|
|
{
|
2013-03-05 03:17:46 +00:00
|
|
|
char path[FILE_MAX]; /* original full path of item */
|
|
|
|
char dir[FILE_MAX]; /* directory part of src_dir */
|
|
|
|
char base[FILE_MAX]; /* basename part of src_dir */
|
2012-05-12 15:13:06 +00:00
|
|
|
char blend_dir[FILE_MAX]; /* directory, where current .blend file resides */
|
2010-02-26 11:50:59 +00:00
|
|
|
char dest_path[FILE_MAX];
|
|
|
|
char rel_dir[FILE_MAX];
|
|
|
|
int len;
|
|
|
|
|
|
|
|
if (abs)
|
2012-05-12 15:13:06 +00:00
|
|
|
abs[0] = 0;
|
2010-02-26 11:50:59 +00:00
|
|
|
|
|
|
|
if (rel)
|
2012-05-12 15:13:06 +00:00
|
|
|
rel[0] = 0;
|
2010-02-26 11:50:59 +00:00
|
|
|
|
2011-10-21 02:13:36 +00:00
|
|
|
BLI_split_dir_part(base_dir, blend_dir, sizeof(blend_dir));
|
2010-02-26 11:50:59 +00:00
|
|
|
|
2012-05-12 15:13:06 +00:00
|
|
|
if (src_dir[0] == '\0')
|
2012-06-22 15:38:49 +00:00
|
|
|
return BLI_REBASE_NO_SRCDIR;
|
2010-02-26 11:50:59 +00:00
|
|
|
|
|
|
|
BLI_strncpy(path, src_dir, sizeof(path));
|
|
|
|
|
|
|
|
/* expand "//" in filename and get absolute path */
|
2010-03-09 17:36:23 +00:00
|
|
|
BLI_path_abs(path, base_dir);
|
2010-02-26 11:50:59 +00:00
|
|
|
|
|
|
|
/* get the directory part */
|
2011-10-15 03:56:05 +00:00
|
|
|
BLI_split_dirfile(path, dir, base, sizeof(dir), sizeof(base));
|
2010-02-26 11:50:59 +00:00
|
|
|
|
2012-05-12 15:13:06 +00:00
|
|
|
len = strlen(blend_dir);
|
2010-02-26 11:50:59 +00:00
|
|
|
|
|
|
|
rel_dir[0] = 0;
|
|
|
|
|
|
|
|
/* if image is "below" current .blend file directory */
|
2012-12-25 14:09:51 +00:00
|
|
|
if (!BLI_path_ncmp(path, blend_dir, len)) {
|
2010-02-26 11:50:59 +00:00
|
|
|
|
2011-04-06 06:03:48 +00:00
|
|
|
if (BLI_path_cmp(dir, blend_dir) == 0) {
|
2013-03-05 03:17:46 +00:00
|
|
|
/* image is directly in .blend file parent directory => put directly in dest_dir */
|
2011-02-13 03:21:27 +00:00
|
|
|
BLI_join_dirfile(dest_path, sizeof(dest_path), dest_dir, base);
|
2010-02-26 11:50:59 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-03-05 03:17:46 +00:00
|
|
|
/* "below" (in subdirectory of .blend file parent directory) => put in same relative directory structure in dest_dir */
|
2010-02-26 11:50:59 +00:00
|
|
|
/* rel = image_path_dir - blend_dir */
|
|
|
|
BLI_strncpy(rel_dir, dir + len, sizeof(rel_dir));
|
2013-03-05 03:17:46 +00:00
|
|
|
/* subdirectories relative to blend_dir */
|
2011-02-13 03:21:27 +00:00
|
|
|
BLI_join_dirfile(dest_path, sizeof(dest_path), dest_dir, rel_dir);
|
2013-03-05 03:17:46 +00:00
|
|
|
/* same subdirectories relative to dest_dir */
|
2013-07-24 21:25:06 +00:00
|
|
|
BLI_path_append(dest_path, sizeof(dest_path), base);
|
2013-03-05 03:17:46 +00:00
|
|
|
/* keeping original item basename */
|
2010-02-26 11:50:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2013-03-05 03:17:46 +00:00
|
|
|
/* image is out of current directory -- just put straight in dest_dir */
|
2010-02-26 11:50:59 +00:00
|
|
|
else {
|
2011-02-13 03:21:27 +00:00
|
|
|
BLI_join_dirfile(dest_path, sizeof(dest_path), dest_dir, base);
|
2010-02-26 11:50:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (abs)
|
2011-05-02 10:22:49 +00:00
|
|
|
BLI_strncpy(abs, dest_path, abs_len);
|
2010-02-26 11:50:59 +00:00
|
|
|
|
|
|
|
if (rel) {
|
2011-05-02 10:22:49 +00:00
|
|
|
strncat(rel, rel_dir, rel_len);
|
2013-03-05 03:17:46 +00:00
|
|
|
strncat(rel, base, rel_len); /* FIXME: could overflow rel area! */
|
2010-02-26 11:50:59 +00:00
|
|
|
}
|
|
|
|
|
2012-07-01 09:54:44 +00:00
|
|
|
/* return 2 if (src == dest) */
|
2011-04-06 06:03:48 +00:00
|
|
|
if (BLI_path_cmp(path, dest_path) == 0) {
|
2012-03-31 00:59:17 +00:00
|
|
|
// if (G.debug & G_DEBUG) printf("%s and %s are the same file\n", path, dest_path);
|
2012-06-22 15:38:49 +00:00
|
|
|
return BLI_REBASE_IDENTITY;
|
2010-02-26 11:50:59 +00:00
|
|
|
}
|
|
|
|
|
2012-06-22 15:38:49 +00:00
|
|
|
return BLI_REBASE_OK;
|
2010-02-26 11:50:59 +00:00
|
|
|
}
|
2014-05-19 00:00:59 +10:00
|
|
|
#endif
|
|
|
|
|
2010-02-26 11:50:59 +00:00
|
|
|
|
2013-03-04 19:27:51 +00:00
|
|
|
/**
|
|
|
|
* Returns pointer to the leftmost path separator in string. Not actually used anywhere.
|
|
|
|
*/
|
|
|
|
const char *BLI_first_slash(const char *string)
|
2011-09-28 05:53:40 +00:00
|
|
|
{
|
2014-04-27 00:20:55 +10:00
|
|
|
const char * const ffslash = strchr(string, '/');
|
|
|
|
const char * const fbslash = strchr(string, '\\');
|
2010-10-27 06:41:48 +00:00
|
|
|
|
|
|
|
if (!ffslash) return fbslash;
|
|
|
|
else if (!fbslash) return ffslash;
|
|
|
|
|
2016-05-03 18:16:06 +10:00
|
|
|
return (ffslash < fbslash) ? ffslash : fbslash;
|
2010-10-27 06:41:48 +00:00
|
|
|
}
|
|
|
|
|
2013-03-04 19:27:51 +00:00
|
|
|
/**
|
|
|
|
* Returns pointer to the rightmost path separator in string.
|
|
|
|
*/
|
|
|
|
const char *BLI_last_slash(const char *string)
|
2011-09-28 05:53:40 +00:00
|
|
|
{
|
2013-03-04 19:27:51 +00:00
|
|
|
const char * const lfslash = strrchr(string, '/');
|
|
|
|
const char * const lbslash = strrchr(string, '\\');
|
2010-10-27 06:41:48 +00:00
|
|
|
|
|
|
|
if (!lfslash) return lbslash;
|
|
|
|
else if (!lbslash) return lfslash;
|
|
|
|
|
2016-05-03 18:16:06 +10:00
|
|
|
return (lfslash > lbslash) ? lfslash : lbslash;
|
2010-10-27 06:41:48 +00:00
|
|
|
}
|
|
|
|
|
2013-03-04 19:27:51 +00:00
|
|
|
/**
|
|
|
|
* Appends a slash to string if there isn't one there already.
|
|
|
|
* Returns the new length of the string.
|
|
|
|
*/
|
2011-09-28 05:53:40 +00:00
|
|
|
int BLI_add_slash(char *string)
|
|
|
|
{
|
2010-10-27 06:41:48 +00:00
|
|
|
int len = strlen(string);
|
2012-05-12 15:13:06 +00:00
|
|
|
if (len == 0 || string[len - 1] != SEP) {
|
2011-10-11 05:21:24 +00:00
|
|
|
string[len] = SEP;
|
2012-05-12 15:13:06 +00:00
|
|
|
string[len + 1] = '\0';
|
|
|
|
return len + 1;
|
2010-10-27 06:41:48 +00:00
|
|
|
}
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2013-03-04 19:27:51 +00:00
|
|
|
/**
|
|
|
|
* Removes the last slash and everything after it to the end of string, if there is one.
|
|
|
|
*/
|
2011-09-28 05:53:40 +00:00
|
|
|
void BLI_del_slash(char *string)
|
|
|
|
{
|
2010-10-27 06:41:48 +00:00
|
|
|
int len = strlen(string);
|
|
|
|
while (len) {
|
2012-05-12 15:13:06 +00:00
|
|
|
if (string[len - 1] == SEP) {
|
|
|
|
string[len - 1] = '\0';
|
2010-10-27 06:41:48 +00:00
|
|
|
len--;
|
2012-03-24 06:18:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2010-10-27 06:41:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-02-26 11:50:59 +00:00
|
|
|
|
2014-07-31 01:40:05 +10:00
|
|
|
/**
|
|
|
|
* Changes to the path separators to the native ones for this OS.
|
|
|
|
*/
|
|
|
|
void BLI_path_native_slash(char *path)
|
|
|
|
{
|
|
|
|
#ifdef WIN32
|
|
|
|
if (path && BLI_strnlen(path, 3) > 2) {
|
2015-06-30 15:18:03 +10:00
|
|
|
BLI_str_replace_char(path + 2, '/', '\\');
|
2014-07-31 01:40:05 +10:00
|
|
|
}
|
|
|
|
#else
|
2015-06-30 15:18:03 +10:00
|
|
|
BLI_str_replace_char(path + BLI_path_unc_prefix_len(path), '\\', '/');
|
2014-07-31 01:40:05 +10:00
|
|
|
#endif
|
|
|
|
}
|