658c55cd75f235065829ec95adfe3827f49eabce
[blender.git] / source / blender / blenlib / intern / path_util.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  *
27  * various string, file, list operations.
28  */
29
30 /** \file blender/blenlib/intern/path_util.c
31  *  \ingroup bli
32  */
33
34 #include <ctype.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <assert.h>
38
39 #include "DNA_listBase.h"
40
41 #include "BLI_utildefines.h"
42 #include "BLI_fileops.h"
43 #include "BLI_path_util.h"
44 #include "BLI_string.h"
45 #include "BLI_string_utf8.h"
46 #include "BLI_fnmatch.h"
47
48 #ifdef WIN32
49 #  include "utf_winfunc.h"
50 #  include "utfconv.h"
51 #  include <io.h>
52 #  ifdef _WIN32_IE
53 #    undef _WIN32_IE
54 #  endif
55 #  define _WIN32_IE 0x0501
56 #  include <windows.h>
57 #  include <shlobj.h>
58 #  include "BLI_winstuff.h"
59 #  include "BLI_alloca.h"
60 #else
61 #  include "unistd.h"
62 #endif /* WIN32 */
63
64 #include "MEM_guardedalloc.h"
65
66 /* local */
67 #define UNIQUE_NAME_MAX 128
68
69 /* Declarations */
70
71 #ifdef WIN32
72
73 /* return true if the path is absolute ie starts with a drive specifier (eg A:\) or is a UNC path */
74 static bool BLI_path_is_abs(const char *name);
75
76 #endif  /* WIN32 */
77
78 /* implementation */
79
80 /**
81  * Looks for a sequence of decimal digits in string, preceding any filename extension,
82  * returning the integer value if found, or 0 if not.
83  *
84  * \param string  String to scan.
85  * \param head  Optional area to return copy of part of string prior to digits, or before dot if no digits.
86  * \param tail  Optional area to return copy of part of string following digits, or from dot if no digits.
87  * \param numlen  Optional to return number of digits found.
88  */
89 int BLI_stringdec(const char *string, char *head, char *tail, unsigned short *numlen)
90 {
91         unsigned int nums = 0, nume = 0;
92         int i;
93         bool found_digit = false;
94         const char * const lslash = BLI_last_slash(string);
95         const unsigned int string_len = strlen(string);
96         const unsigned int lslash_len = lslash != NULL ? (int)(lslash - string) : 0;
97         unsigned int name_end = string_len;
98
99         while (name_end > lslash_len && string[--name_end] != '.') {} /* name ends at dot if present */
100         if (name_end == lslash_len && string[name_end] != '.') name_end = string_len;
101
102         for (i = name_end - 1; i >= (int)lslash_len; i--) {
103                 if (isdigit(string[i])) {
104                         if (found_digit) {
105                                 nums = i;
106                         }
107                         else {
108                                 nume = i;
109                                 nums = i;
110                                 found_digit = true;
111                         }
112                 }
113                 else {
114                         if (found_digit) break;
115                 }
116         }
117
118         if (found_digit) {
119                 if (tail) strcpy(tail, &string[nume + 1]);
120                 if (head) {
121                         strcpy(head, string);
122                         head[nums] = 0;
123                 }
124                 if (numlen) *numlen = nume - nums + 1;
125                 return ((int)atoi(&(string[nums])));
126         }
127         else {
128                 if (tail) strcpy(tail, string + name_end);
129                 if (head) {
130                         /* name_end points to last character of head,
131                          * make it +1 so null-terminator is nicely placed
132                          */
133                         BLI_strncpy(head, string, name_end + 1);
134                 }
135                 if (numlen) *numlen = 0;
136                 return 0;
137         }
138 }
139
140
141 /**
142  * Returns in area pointed to by string a string of the form "<head><pic><tail>", where pic
143  * is formatted as numlen digits with leading zeroes.
144  */
145 void BLI_stringenc(char *string, const char *head, const char *tail, unsigned short numlen, int pic)
146 {
147         sprintf(string, "%s%.*d%s", head, numlen, MAX2(0, pic), tail);
148 }
149
150 /**
151  * Looks for a numeric suffix preceded by delim character on the end of
152  * name, puts preceding part into *left and value of suffix into *nr.
153  * Returns the length of *left.
154  *
155  * Foo.001 -> "Foo", 1
156  * Returning the length of "Foo"
157  *
158  * \param left  Where to return copy of part preceding delim
159  * \param nr  Where to return value of numeric suffix
160  * \param name  String to split
161  * \param delim  Delimiter character
162  * \return  Length of \a left
163  */
164 int BLI_split_name_num(char *left, int *nr, const char *name, const char delim)
165 {
166         const int name_len = strlen(name);
167
168         *nr = 0;
169         memcpy(left, name, (name_len + 1) * sizeof(char));
170
171         /* name doesn't end with a delimiter "foo." */
172         if ((name_len > 1 && name[name_len - 1] == delim) == 0) {
173                 int a = name_len;
174                 while (a--) {
175                         if (name[a] == delim) {
176                                 left[a] = '\0';  /* truncate left part here */
177                                 *nr = atol(name + a + 1);
178                                 /* casting down to an int, can overflow for large numbers */
179                                 if (*nr < 0)
180                                         *nr = 0;
181                                 return a;
182                         }
183                         else if (isdigit(name[a]) == 0) {
184                                 /* non-numeric suffix - give up */
185                                 break;
186                         }
187                 }
188         }
189
190         return name_len;
191 }
192
193 /**
194  * Looks for a string of digits within name (using BLI_stringdec) and adjusts it by add.
195  */
196 void BLI_newname(char *name, int add)
197 {
198         char head[UNIQUE_NAME_MAX], tail[UNIQUE_NAME_MAX];
199         int pic;
200         unsigned short digits;
201         
202         pic = BLI_stringdec(name, head, tail, &digits);
203         
204         /* are we going from 100 -> 99 or from 10 -> 9 */
205         if (add < 0 && digits < 4 && digits > 0) {
206                 int i, exp;
207                 exp = 1;
208                 for (i = digits; i > 1; i--) exp *= 10;
209                 if (pic >= exp && (pic + add) < exp) digits--;
210         }
211         
212         pic += add;
213         
214         if (digits == 4 && pic < 0) pic = 0;
215         BLI_stringenc(name, head, tail, digits, pic);
216 }
217
218 /**
219  * Ensures name is unique (according to criteria specified by caller in unique_check callback),
220  * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
221  *
222  * \param unique_check  Return true if name is not unique
223  * \param arg  Additional arg to unique_check--meaning is up to caller
224  * \param defname  To initialize name if latter is empty
225  * \param delim  Delimits numeric suffix in name
226  * \param name  Name to be ensured unique
227  * \param name_len  Maximum length of name area
228  * \return true if there if the name was changed
229  */
230 bool BLI_uniquename_cb(bool (*unique_check)(void *arg, const char *name),
231                        void *arg, const char *defname, char delim, char *name, int name_len)
232 {
233         if (name[0] == '\0') {
234                 BLI_strncpy(name, defname, name_len);
235         }
236
237         if (unique_check(arg, name)) {
238                 char numstr[16];
239                 char tempname[UNIQUE_NAME_MAX];
240                 char left[UNIQUE_NAME_MAX];
241                 int number;
242                 int len = BLI_split_name_num(left, &number, name, delim);
243                 do {
244                         /* add 1 to account for \0 */
245                         const int numlen = BLI_snprintf(numstr, sizeof(numstr), "%c%03d", delim, ++number) + 1;
246
247                         /* highly unlikely the string only has enough room for the number
248                          * but support anyway */
249                         if ((len == 0) || (numlen >= name_len)) {
250                                 /* number is know not to be utf-8 */
251                                 BLI_strncpy(tempname, numstr, name_len);
252                         }
253                         else {
254                                 char *tempname_buf;
255                                 tempname_buf = tempname + BLI_strncpy_utf8_rlen(tempname, left, name_len - numlen);
256                                 memcpy(tempname_buf, numstr, numlen);
257                         }
258                 } while (unique_check(arg, tempname));
259
260                 BLI_strncpy(name, tempname, name_len);
261                 
262                 return true;
263         }
264         
265         return false;
266 }
267
268 /* little helper macro for BLI_uniquename */
269 #ifndef GIVE_STRADDR
270 #  define GIVE_STRADDR(data, offset) ( ((char *)data) + offset)
271 #endif
272
273 /* Generic function to set a unique name. It is only designed to be used in situations
274  * where the name is part of the struct, and also that the name is at most UNIQUE_NAME_MAX chars long.
275  * 
276  * For places where this is used, see constraint.c for example...
277  *
278  *  name_offs: should be calculated using offsetof(structname, membername) macro from stddef.h
279  *  len: maximum length of string (to prevent overflows, etc.)
280  *  defname: the name that should be used by default if none is specified already
281  *  delim: the character which acts as a delimiter between parts of the name
282  */
283 static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offs)
284 {
285         Link *link;
286
287         for (link = list->first; link; link = link->next) {
288                 if (link != vlink) {
289                         if (STREQ(GIVE_STRADDR(link, name_offs), name)) {
290                                 return true;
291                         }
292                 }
293         }
294
295         return false;
296 }
297
298 static bool uniquename_unique_check(void *arg, const char *name)
299 {
300         struct {ListBase *lb; void *vlink; int name_offs; } *data = arg;
301         return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offs);
302 }
303
304 /**
305  * Ensures that the specified block has a unique name within the containing list,
306  * incrementing its numeric suffix as necessary. Returns true if name had to be adjusted.
307  *
308  * \param list  List containing the block
309  * \param vlink  The block to check the name for
310  * \param defname  To initialize block name if latter is empty
311  * \param delim  Delimits numeric suffix in name
312  * \param name_offs  Offset of name within block structure
313  * \param name_len  Maximum length of name area
314  */
315 bool BLI_uniquename(ListBase *list, void *vlink, const char *defname, char delim, int name_offs, int name_len)
316 {
317         struct {ListBase *lb; void *vlink; int name_offs; } data;
318         data.lb = list;
319         data.vlink = vlink;
320         data.name_offs = name_offs;
321
322         assert((name_len > 1) && (name_len <= UNIQUE_NAME_MAX));
323
324         /* See if we are given an empty string */
325         if (ELEM(NULL, vlink, defname))
326                 return false;
327
328         return BLI_uniquename_cb(uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len);
329 }
330
331 static int BLI_path_unc_prefix_len(const char *path); /* defined below in same file */
332
333 /* ******************** string encoding ***************** */
334
335 /* This is quite an ugly function... its purpose is to
336  * take the dir name, make it absolute, and clean it up, replacing
337  * excess file entry stuff (like /tmp/../tmp/../)
338  * note that dir isn't protected for max string names... 
339  * 
340  * If relbase is NULL then its ignored
341  */
342
343 void BLI_cleanup_path(const char *relabase, char *path)
344 {
345         ptrdiff_t a;
346         char *start, *eind;
347         if (relabase) {
348                 BLI_path_abs(path, relabase);
349         }
350         else {
351                 if (path[0] == '/' && path[1] == '/') {
352                         if (path[2] == '\0') {
353                                 return; /* path is "//" - cant clean it */
354                         }
355                         path = path + 2;  /* leave the initial "//" untouched */
356                 }
357         }
358         
359         /* Note
360          *   memmove(start, eind, strlen(eind) + 1);
361          * is the same as
362          *   strcpy(start, eind);
363          * except strcpy should not be used because there is overlap,
364          * so use memmove's slightly more obscure syntax - Campbell
365          */
366         
367 #ifdef WIN32
368         while ( (start = strstr(path, "\\..\\")) ) {
369                 eind = start + strlen("\\..\\") - 1;
370                 a = start - path - 1;
371                 while (a > 0) {
372                         if (path[a] == '\\') break;
373                         a--;
374                 }
375                 if (a < 0) {
376                         break;
377                 }
378                 else {
379                         memmove(path + a, eind, strlen(eind) + 1);
380                 }
381         }
382
383         while ( (start = strstr(path, "\\.\\")) ) {
384                 eind = start + strlen("\\.\\") - 1;
385                 memmove(start, eind, strlen(eind) + 1);
386         }
387
388         /* remove two consecutive backslashes, but skip the UNC prefix,
389          * which needs to be preserved */
390         while ( (start = strstr(path + BLI_path_unc_prefix_len(path), "\\\\")) ) {
391                 eind = start + strlen("\\\\") - 1;
392                 memmove(start, eind, strlen(eind) + 1);
393         }
394 #else
395         while ( (start = strstr(path, "/../")) ) {
396                 a = start - path - 1;
397                 if (a > 0) {
398                         /* <prefix>/<parent>/../<postfix> => <prefix>/<postfix> */
399                         eind = start + (4 - 1) /* strlen("/../") - 1 */; /* strip "/.." and keep last "/" */
400                         while (a > 0 && path[a] != '/') { /* find start of <parent> */
401                                 a--;
402                         }
403                         memmove(path + a, eind, strlen(eind) + 1);
404                 }
405                 else {
406                         /* support for odd paths: eg /../home/me --> /home/me
407                          * this is a valid path in blender but we cant handle this the usual way below
408                          * simply strip this prefix then evaluate the path as usual.
409                          * pythons os.path.normpath() does this */
410
411                         /* Note: previous version of following call used an offset of 3 instead of 4,
412                          * which meant that the "/../home/me" example actually became "home/me".
413                          * Using offset of 3 gives behaviour consistent with the abovementioned
414                          * Python routine. */
415                         memmove(path, path + 3, strlen(path + 3) + 1);
416                 }
417         }
418
419         while ( (start = strstr(path, "/./")) ) {
420                 eind = start + (3 - 1) /* strlen("/./") - 1 */;
421                 memmove(start, eind, strlen(eind) + 1);
422         }
423
424         while ( (start = strstr(path, "//")) ) {
425                 eind = start + (2 - 1) /* strlen("//") - 1 */;
426                 memmove(start, eind, strlen(eind) + 1);
427         }
428 #endif
429 }
430
431 void BLI_cleanup_dir(const char *relabase, char *dir)
432 {
433         BLI_cleanup_path(relabase, dir);
434         BLI_add_slash(dir);
435
436 }
437
438 void BLI_cleanup_file(const char *relabase, char *path)
439 {
440         BLI_cleanup_path(relabase, path);
441         BLI_del_slash(path);
442 }
443
444
445 /**
446  * Make given name safe to be used in paths.
447  *
448  * \return true if \a fname was changed, false otherwise.
449  *
450  * For now, simply replaces reserved chars (as listed in
451  * http://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words )
452  * by underscores ('_').
453  *
454  * \note Space case ' ' is a bit of an edge case here - in theory it is allowed, but again can be an issue
455  *       in some cases, so we simply replace it by an underscore too (good practice anyway).
456  *
457  * \note On Windows, it also ensures there is no '.' (dot char) at the end of the file, this can lead to issues...
458  *
459  * \note On Windows, it also checks for forbidden names
460  *       (see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx ).
461  */
462 bool BLI_filename_make_safe(char *fname)
463 {
464         const char *invalid =     "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
465                               "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
466                               "/\\?%*:|\"<> ";
467         char *fn;
468         bool changed = false;
469
470         if (*fname == '\0') {
471                 return changed;
472         }
473
474         for (fn = fname; *fn && (fn = strpbrk(fn, invalid)); fn++) {
475                 *fn = '_';
476                 changed = true;
477         }
478
479         /* Forbid only dots. */
480         for (fn = fname; *fn == '.'; fn++);
481         if (*fn == '\0') {
482                 *fname = '_';
483                 changed = true;
484         }
485
486 #ifdef WIN32
487         {
488                 const size_t len = strlen(fname);
489                 const char *invalid_names[] = {
490                     "con", "prn", "aux", "null",
491                     "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9",
492                     "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9",
493                     NULL
494                 };
495                 char *lower_fname = BLI_strdup(fname);
496                 const char **iname;
497
498                 /* Forbid trailing dot (trailing space has already been replaced above). */
499                 if (fname[len - 1] == '.') {
500                         fname[len - 1] = '_';
501                         changed = true;
502                 }
503
504                 /* Check for forbidden names - not we have to check all combination of upper and lower cases, hence the usage
505                  * of lower_fname (more efficient than using BLI_strcasestr repeatedly). */
506                 BLI_str_tolower_ascii(lower_fname, len);
507                 for (iname = invalid_names; *iname; iname++) {
508                         if (strstr(lower_fname, *iname) == lower_fname) {
509                                 const size_t iname_len = strlen(*iname);
510                                 /* Only invalid if the whole name is made of the invalid chunk, or it has an (assumed extension) dot
511                                  * just after. This means it will also catch 'valid' names like 'aux.foo.bar', but should be
512                                  * good enough for us! */
513                                 if ((iname_len == len) || (lower_fname[iname_len] == '.')) {
514                                         *fname = '_';
515                                         changed = true;
516                                         break;
517                                 }
518                         }
519                 }
520
521                 MEM_freeN(lower_fname);
522         }
523 #endif
524
525         return changed;
526 }
527
528 /**
529  * Make given path OS-safe.
530  *
531  * \return true if \a path was changed, false otherwise.
532  */
533 bool BLI_path_make_safe(char *path)
534 {
535         /* Simply apply BLI_filename_make_safe() over each component of the path.
536          * Luckily enough, same 'safe' rules applies to filenames and dirnames. */
537         char *curr_slash, *curr_path = path;
538         bool changed = false;
539         bool skip_first = false;
540
541 #ifdef WIN32
542         if (BLI_path_is_abs(path)) {
543                 /* Do not make safe 'C:' in 'C:\foo\bar'... */
544                 skip_first = true;
545         }
546 #endif
547
548         for (curr_slash = (char *)BLI_first_slash(curr_path); curr_slash; curr_slash = (char *)BLI_first_slash(curr_path)) {
549                 const char backup = *curr_slash;
550                 *curr_slash = '\0';
551                 if (!skip_first && (*curr_path != '\0') && BLI_filename_make_safe(curr_path)) {
552                         changed = true;
553                 }
554                 skip_first = false;
555                 curr_path = curr_slash + 1;
556                 *curr_slash = backup;
557         }
558         if (BLI_filename_make_safe(curr_path)) {
559                 changed = true;
560         }
561
562         return changed;
563 }
564
565 /**
566  * Does path begin with the special "//" prefix that Blender uses to indicate
567  * a path relative to the .blend file.
568  */
569 bool BLI_path_is_rel(const char *path)
570 {
571         return path[0] == '/' && path[1] == '/';
572 }
573
574 /* return true if the path is a UNC share */
575 bool BLI_path_is_unc(const char *name)
576 {
577         return name[0] == '\\' && name[1] == '\\';
578 }
579
580 /**
581  * Returns the length of the identifying prefix
582  * of a UNC path which can start with '\\' (short version)
583  * or '\\?\' (long version)
584  * If the path is not a UNC path, return 0
585  */
586 static int BLI_path_unc_prefix_len(const char *path)
587 {
588         if (BLI_path_is_unc(path)) {
589                 if ((path[2] == '?') && (path[3] == '\\') ) {
590                         /* we assume long UNC path like \\?\server\share\folder etc... */
591                         return 4;
592                 }
593                 else {
594                         return 2;
595                 }
596         }
597
598         return 0;
599 }
600
601 #if defined(WIN32)
602
603 /* return true if the path is absolute ie starts with a drive specifier (eg A:\) or is a UNC path */
604 static bool BLI_path_is_abs(const char *name)
605 {
606         return (name[1] == ':' && (name[2] == '\\' || name[2] == '/') ) || BLI_path_is_unc(name);
607 }
608
609 static wchar_t *next_slash(wchar_t *path)
610 {
611         wchar_t *slash = path;
612         while (*slash && *slash != L'\\') slash++;
613         return slash;
614 }
615
616 /* adds a slash if the unc path points sto a share */
617 static void BLI_path_add_slash_to_share(wchar_t *uncpath)
618 {
619         wchar_t *slash_after_server = next_slash(uncpath + 2);
620         if (*slash_after_server) {
621                 wchar_t *slash_after_share = next_slash(slash_after_server + 1);
622                 if (!(*slash_after_share)) {
623                         slash_after_share[0] = L'\\';
624                         slash_after_share[1] = L'\0';
625                 }
626         }
627 }
628
629 static void BLI_path_unc_to_short(wchar_t *unc)
630 {
631         wchar_t tmp[PATH_MAX];
632
633         int len = wcslen(unc);
634         int copy_start = 0;
635         /* convert:
636          *    \\?\UNC\server\share\folder\... to \\server\share\folder\...
637          *    \\?\C:\ to C:\ and \\?\C:\folder\... to C:\folder\...
638          */
639         if ((len > 3) &&
640             (unc[0] ==  L'\\') &&
641             (unc[1] ==  L'\\') &&
642             (unc[2] ==  L'?') &&
643             ((unc[3] ==  L'\\') || (unc[3] ==  L'/')))
644         {
645                 if ((len > 5) && (unc[5] ==  L':')) {
646                         wcsncpy(tmp, unc + 4, len - 4);
647                         tmp[len - 4] = L'\0';
648                         wcscpy(unc, tmp);
649                 }
650                 else if ((len > 7) && (wcsncmp(&unc[4], L"UNC", 3) == 0) &&
651                          ((unc[7] ==  L'\\') || (unc[7] ==  L'/')))
652                 {
653                         tmp[0] = L'\\';
654                         tmp[1] = L'\\';
655                         wcsncpy(tmp + 2, unc + 8, len - 8);
656                         tmp[len - 6] = L'\0';
657                         wcscpy(unc, tmp);
658                 }
659         }
660 }
661
662 void BLI_cleanup_unc(char *path, int maxlen)
663 {
664         wchar_t *tmp_16 = alloc_utf16_from_8(path, 1);
665         BLI_cleanup_unc_16(tmp_16);
666         conv_utf_16_to_8(tmp_16, path, maxlen);
667 }
668
669 void BLI_cleanup_unc_16(wchar_t *path_16)
670 {
671         BLI_path_unc_to_short(path_16);
672         BLI_path_add_slash_to_share(path_16);
673 }
674 #endif
675
676 /**
677  * Replaces *file with a relative version (prefixed by "//") such that BLI_path_abs, given
678  * the same *relfile, will convert it back to its original value.
679  */
680 void BLI_path_rel(char *file, const char *relfile)
681 {
682         const char *lslash;
683         char temp[FILE_MAX];
684         char res[FILE_MAX];
685         
686         /* if file is already relative, bail out */
687         if (BLI_path_is_rel(file)) {
688                 return;
689         }
690         
691         /* also bail out if relative path is not set */
692         if (relfile[0] == '\0') {
693                 return;
694         }
695
696 #ifdef WIN32
697         if (BLI_strnlen(relfile, 3) > 2 && !BLI_path_is_abs(relfile)) {
698                 char *ptemp;
699                 /* fix missing volume name in relative base,
700                  * can happen with old recent-files.txt files */
701                 get_default_root(temp);
702                 ptemp = &temp[2];
703                 if (relfile[0] != '\\' && relfile[0] != '/') {
704                         ptemp++;
705                 }
706                 BLI_strncpy(ptemp, relfile, FILE_MAX - 3);
707         }
708         else {
709                 BLI_strncpy(temp, relfile, FILE_MAX);
710         }
711
712         if (BLI_strnlen(file, 3) > 2) {
713                 bool is_unc = BLI_path_is_unc(file);
714
715                 /* Ensure paths are both UNC paths or are both drives */
716                 if (BLI_path_is_unc(temp) != is_unc) {
717                         return;
718                 }
719
720                 /* Ensure both UNC paths are on the same share */
721                 if (is_unc) {
722                         int off;
723                         int slash = 0;
724                         for (off = 0; temp[off] && slash < 4; off++) {
725                                 if (temp[off] != file[off])
726                                         return;
727
728                                 if (temp[off] == '\\')
729                                         slash++;
730                         }
731                 }
732                 else if (temp[1] == ':' && file[1] == ':' && temp[0] != file[0]) {
733                         return;
734                 }
735         }
736 #else
737         BLI_strncpy(temp, relfile, FILE_MAX);
738 #endif
739
740         BLI_str_replace_char(temp + BLI_path_unc_prefix_len(temp), '\\', '/');
741         BLI_str_replace_char(file + BLI_path_unc_prefix_len(file), '\\', '/');
742         
743         /* remove /./ which confuse the following slash counting... */
744         BLI_cleanup_path(NULL, file);
745         BLI_cleanup_path(NULL, temp);
746         
747         /* the last slash in the file indicates where the path part ends */
748         lslash = BLI_last_slash(temp);
749
750         if (lslash) {
751                 /* find the prefix of the filename that is equal for both filenames.
752                  * This is replaced by the two slashes at the beginning */
753                 const char *p = temp;
754                 const char *q = file;
755                 char *r = res;
756
757 #ifdef WIN32
758                 while (tolower(*p) == tolower(*q))
759 #else
760                 while (*p == *q)
761 #endif
762                 {
763                         p++;
764                         q++;
765
766                         /* don't search beyond the end of the string
767                          * in the rare case they match */
768                         if ((*p == '\0') || (*q == '\0')) {
769                                 break;
770                         }
771                 }
772
773                 /* we might have passed the slash when the beginning of a dir matches 
774                  * so we rewind. Only check on the actual filename
775                  */
776                 if (*q != '/') {
777                         while ( (q >= file) && (*q != '/') ) { --q; --p; }
778                 }
779                 else if (*p != '/') {
780                         while ( (p >= temp) && (*p != '/') ) { --p; --q; }
781                 }
782                 
783                 r += BLI_strcpy_rlen(r, "//");
784
785                 /* p now points to the slash that is at the beginning of the part
786                  * where the path is different from the relative path. 
787                  * We count the number of directories we need to go up in the
788                  * hierarchy to arrive at the common 'prefix' of the path
789                  */
790                 if (p < temp) p = temp;
791                 while (p && p < lslash) {
792                         if (*p == '/') {
793                                 r += BLI_strcpy_rlen(r, "../");
794                         }
795                         p++;
796                 }
797
798                 /* don't copy the slash at the beginning */
799                 r += BLI_strcpy_rlen(r, q + 1);
800                 
801 #ifdef  WIN32
802                 BLI_str_replace_char(res + 2, '/', '\\');
803 #endif
804                 strcpy(file, res);
805         }
806 }
807
808 /**
809  * Appends a suffix to the string, fitting it before the extension
810  *
811  * string = Foo.png, suffix = 123, separator = _
812  * Foo.png -> Foo_123.png
813  *
814  * \param string  original (and final) string
815  * \param maxlen  Maximum length of string
816  * \param suffix  String to append to the original string
817  * \param sep Optional separator character
818  * \return  true if succeeded
819  */
820 bool BLI_path_suffix(char *string, size_t maxlen, const char *suffix, const char *sep)
821 {
822         const size_t string_len = strlen(string);
823         const size_t suffix_len = strlen(suffix);
824         const size_t sep_len = strlen(sep);
825         ssize_t a;
826         char extension[FILE_MAX];
827         bool has_extension = false;
828
829         if (string_len + sep_len + suffix_len >= maxlen)
830                 return false;
831
832         for (a = string_len - 1; a >= 0; a--) {
833                 if (string[a] == '.') {
834                         has_extension = true;
835                         break;
836                 }
837                 else if (ELEM(string[a], '/', '\\')) {
838                         break;
839                 }
840         }
841
842         if (!has_extension)
843                 a = string_len;
844
845         BLI_strncpy(extension, string + a, sizeof(extension));
846         sprintf(string + a, "%s%s%s", sep, suffix, extension);
847         return true;
848 }
849
850 /**
851  * Replaces path with the path of its parent directory, returning true if
852  * it was able to find a parent directory within the pathname.
853  */
854 bool BLI_parent_dir(char *path)
855 {
856         const char parent_dir[] = {'.', '.', SEP, '\0'}; /* "../" or "..\\" */
857         char tmp[FILE_MAX + 4];
858
859         BLI_join_dirfile(tmp, sizeof(tmp), path, parent_dir);
860         BLI_cleanup_dir(NULL, tmp); /* does all the work of normalizing the path for us */
861
862         if (!BLI_testextensie(tmp, parent_dir)) {
863                 strcpy(path, tmp);  /* We assume pardir is always shorter... */
864                 return true;
865         }
866         else {
867                 return false;
868         }
869 }
870
871 /**
872  * Looks for a sequence of "#" characters in the last slash-separated component of *path,
873  * returning the indexes of the first and one past the last character in the sequence in
874  * *char_start and *char_end respectively. Returns true if such a sequence was found.
875  */
876 static bool stringframe_chars(const char *path, int *char_start, int *char_end)
877 {
878         unsigned int ch_sta, ch_end, i;
879         /* Insert current frame: file### -> file001 */
880         ch_sta = ch_end = 0;
881         for (i = 0; path[i] != '\0'; i++) {
882                 if (path[i] == '\\' || path[i] == '/') {
883                         ch_end = 0; /* this is a directory name, don't use any hashes we found */
884                 }
885                 else if (path[i] == '#') {
886                         ch_sta = i;
887                         ch_end = ch_sta + 1;
888                         while (path[ch_end] == '#') {
889                                 ch_end++;
890                         }
891                         i = ch_end - 1; /* keep searching */
892                         
893                         /* don't break, there may be a slash after this that invalidates the previous #'s */
894                 }
895         }
896
897         if (ch_end) {
898                 *char_start = ch_sta;
899                 *char_end = ch_end;
900                 return true;
901         }
902         else {
903                 *char_start = -1;
904                 *char_end = -1;
905                 return false;
906         }
907 }
908
909 /**
910  * Ensure *path contains at least one "#" character in its last slash-separated
911  * component, appending one digits long if not.
912  */
913 static void ensure_digits(char *path, int digits)
914 {
915         char *file = (char *)BLI_last_slash(path);
916
917         if (file == NULL)
918                 file = path;
919
920         if (strrchr(file, '#') == NULL) {
921                 int len = strlen(file);
922
923                 while (digits--) {
924                         file[len++] = '#';
925                 }
926                 file[len] = '\0';
927         }
928 }
929
930 /**
931  * Replaces "#" character sequence in last slash-separated component of *path
932  * with frame as decimal integer, with leading zeroes as necessary, to make digits digits.
933  */
934 bool BLI_path_frame(char *path, int frame, int digits)
935 {
936         int ch_sta, ch_end;
937
938         if (digits)
939                 ensure_digits(path, digits);
940
941         if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */
942                 char tmp[FILE_MAX];
943                 BLI_snprintf(tmp, sizeof(tmp),
944                              "%.*s%.*d%s",
945                              ch_sta, path, ch_end - ch_sta, frame, path + ch_end);
946                 BLI_strncpy(path, tmp, FILE_MAX);
947                 return true;
948         }
949         return false;
950 }
951
952 /**
953  * Replaces "#" character sequence in last slash-separated component of *path
954  * with sta and end as decimal integers, with leading zeroes as necessary, to make digits
955  * digits each, with a hyphen in-between.
956  */
957 bool BLI_path_frame_range(char *path, int sta, int end, int digits)
958 {
959         int ch_sta, ch_end;
960
961         if (digits)
962                 ensure_digits(path, digits);
963
964         if (stringframe_chars(path, &ch_sta, &ch_end)) { /* warning, ch_end is the last # +1 */
965                 char tmp[FILE_MAX];
966                 BLI_snprintf(tmp, sizeof(tmp),
967                              "%.*s%.*d-%.*d%s",
968                              ch_sta, path, ch_end - ch_sta, sta, ch_end - ch_sta, end, path + ch_end);
969                 BLI_strncpy(path, tmp, FILE_MAX);
970                 return true;
971         }
972         return false;
973 }
974
975 /**
976  * Get the frame from a filename formatted by blender's frame scheme
977  */
978 bool BLI_path_frame_get(char *path, int *r_frame, int *r_numdigits)
979 {
980         if (path && *path) {
981                 char *file = (char *)BLI_last_slash(path);
982                 char *c;
983                 int len, numdigits;
984
985                 numdigits = *r_numdigits = 0;
986
987                 if (file == NULL)
988                         file = path;
989
990                 /* first get the extension part */
991                 len = strlen(file);
992
993                 c = file + len;
994
995                 /* isolate extension */
996                 while (--c != file) {
997                         if (*c == '.') {
998                                 c--;
999                                 break;
1000                         }
1001                 }
1002
1003                 /* find start of number */
1004                 while (c != (file - 1) && isdigit(*c)) {
1005                         c--;
1006                         numdigits++;
1007                 }
1008
1009                 if (numdigits) {
1010                         char prevchar;
1011
1012                         c++;
1013                         prevchar = c[numdigits];
1014                         c[numdigits] = 0;
1015
1016                         /* was the number really an extension? */
1017                         *r_frame = atoi(c);
1018                         c[numdigits] = prevchar;
1019
1020                         *r_numdigits = numdigits;
1021
1022                         return true;
1023                 }
1024         }
1025
1026         return false;
1027 }
1028
1029 void BLI_path_frame_strip(char *path, bool setsharp, char *ext)
1030 {
1031         if (path && *path) {
1032                 char *file = (char *)BLI_last_slash(path);
1033                 char *c, *suffix;
1034                 int len;
1035                 int numdigits = 0;
1036
1037                 if (file == NULL)
1038                         file = path;
1039
1040                 /* first get the extension part */
1041                 len = strlen(file);
1042
1043                 c = file + len;
1044
1045                 /* isolate extension */
1046                 while (--c != file) {
1047                         if (*c == '.') {
1048                                 c--;
1049                                 break;
1050                         }
1051                 }
1052
1053                 suffix = c + 1;
1054
1055                 /* find start of number */
1056                 while (c != (file - 1) && isdigit(*c)) {
1057                         c--;
1058                         numdigits++;
1059                 }
1060
1061                 c++;
1062
1063                 if (numdigits) {
1064                         /* replace the number with the suffix and terminate the string */
1065                         while (numdigits--) {
1066                                 if (ext) *ext++ = *suffix;
1067
1068                                 if (setsharp) *c++ = '#';
1069                                 else *c++ = *suffix;
1070
1071                                 suffix++;
1072                         }
1073                         *c = 0;
1074                         if (ext) *ext = 0;
1075                 }
1076         }
1077 }
1078
1079
1080 /**
1081  * Check if we have '#' chars, usable for #BLI_path_frame, #BLI_path_frame_range
1082  */
1083 bool BLI_path_frame_check_chars(const char *path)
1084 {
1085         int ch_sta, ch_end;  /* dummy args */
1086         return stringframe_chars(path, &ch_sta, &ch_end);
1087 }
1088
1089 /**
1090  * If path begins with "//", strips that and replaces it with basepath directory. Also converts
1091  * a drive-letter prefix to something more sensible if this is a non-drive-letter-based system.
1092  * Returns true if "//" prefix expansion was done.
1093  */
1094 bool BLI_path_abs(char *path, const char *basepath)
1095 {
1096         const bool wasrelative = BLI_path_is_rel(path);
1097         char tmp[FILE_MAX];
1098         char base[FILE_MAX];
1099 #ifdef WIN32
1100
1101         /* without this: "" --> "C:\" */
1102         if (*path == '\0') {
1103                 return wasrelative;
1104         }
1105
1106         /* we are checking here if we have an absolute path that is not in the current
1107          * blend file as a lib main - we are basically checking for the case that a 
1108          * UNIX root '/' is passed.
1109          */
1110         if (!wasrelative && !BLI_path_is_abs(path)) {
1111                 char *p = path;
1112                 get_default_root(tmp);
1113                 // get rid of the slashes at the beginning of the path
1114                 while (*p == '\\' || *p == '/') {
1115                         p++;
1116                 }
1117                 strcat(tmp, p);
1118         }
1119         else {
1120                 BLI_strncpy(tmp, path, FILE_MAX);
1121         }
1122 #else
1123         BLI_strncpy(tmp, path, sizeof(tmp));
1124         
1125         /* Check for loading a windows path on a posix system
1126          * in this case, there is no use in trying C:/ since it 
1127          * will never exist on a unix os.
1128          * 
1129          * Add a / prefix and lowercase the driveletter, remove the :
1130          * C:\foo.JPG -> /c/foo.JPG */
1131         
1132         if (isalpha(tmp[0]) && tmp[1] == ':' && (tmp[2] == '\\' || tmp[2] == '/') ) {
1133                 tmp[1] = tolower(tmp[0]); /* replace ':' with driveletter */
1134                 tmp[0] = '/'; 
1135                 /* '\' the slash will be converted later */
1136         }
1137         
1138 #endif
1139
1140         /* push slashes into unix mode - strings entering this part are
1141          * potentially messed up: having both back- and forward slashes.
1142          * Here we push into one conform direction, and at the end we
1143          * push them into the system specific dir. This ensures uniformity
1144          * of paths and solving some problems (and prevent potential future
1145          * ones) -jesterKing.
1146          * For UNC paths the first characters containing the UNC prefix
1147          * shouldn't be switched as we need to distinguish them from
1148          * paths relative to the .blend file -elubie */
1149         BLI_str_replace_char(tmp + BLI_path_unc_prefix_len(tmp), '\\', '/');
1150
1151         /* Paths starting with // will get the blend file as their base,
1152          * this isn't standard in any os but is used in blender all over the place */
1153         if (wasrelative) {
1154                 const char *lslash;
1155                 BLI_strncpy(base, basepath, sizeof(base));
1156
1157                 /* file component is ignored, so don't bother with the trailing slash */
1158                 BLI_cleanup_path(NULL, base);
1159                 lslash = BLI_last_slash(base);
1160                 BLI_str_replace_char(base + BLI_path_unc_prefix_len(base), '\\', '/');
1161
1162                 if (lslash) {
1163                         const int baselen = (int) (lslash - base) + 1;  /* length up to and including last "/" */
1164                         /* use path for temp storage here, we copy back over it right away */
1165                         BLI_strncpy(path, tmp + 2, FILE_MAX);  /* strip "//" */
1166                         
1167                         memcpy(tmp, base, baselen);  /* prefix with base up to last "/" */
1168                         BLI_strncpy(tmp + baselen, path, sizeof(tmp) - baselen);  /* append path after "//" */
1169                         BLI_strncpy(path, tmp, FILE_MAX);  /* return as result */
1170                 }
1171                 else {
1172                         /* base doesn't seem to be a directory--ignore it and just strip "//" prefix on path */
1173                         BLI_strncpy(path, tmp + 2, FILE_MAX);
1174                 }
1175         }
1176         else {
1177                 /* base ignored */
1178                 BLI_strncpy(path, tmp, FILE_MAX);
1179         }
1180
1181 #ifdef WIN32
1182         /* skip first two chars, which in case of
1183          * absolute path will be drive:/blabla and
1184          * in case of relpath //blabla/. So relpath
1185          * // will be retained, rest will be nice and
1186          * shiny win32 backward slashes :) -jesterKing
1187          */
1188         BLI_str_replace_char(path + 2, '/', '\\');
1189 #endif
1190
1191         /* ensure this is after correcting for path switch */
1192         BLI_cleanup_path(NULL, path);
1193
1194         return wasrelative;
1195 }
1196
1197
1198 /**
1199  * Expands path relative to the current working directory, if it was relative.
1200  * Returns true if such expansion was done.
1201  *
1202  * \note Should only be done with command line paths.
1203  * this is _not_ something blenders internal paths support like the "//" prefix
1204  */
1205 bool BLI_path_cwd(char *path)
1206 {
1207         bool wasrelative = true;
1208         const int filelen = strlen(path);
1209         
1210 #ifdef WIN32
1211         if ((filelen >= 3 && BLI_path_is_abs(path)) || BLI_path_is_unc(path))
1212                 wasrelative = false;
1213 #else
1214         if (filelen >= 2 && path[0] == '/')
1215                 wasrelative = false;
1216 #endif
1217         
1218         if (wasrelative) {
1219                 char cwd[FILE_MAX] = "";
1220                 BLI_current_working_dir(cwd, sizeof(cwd)); /* in case the full path to the blend isn't used */
1221                 
1222                 if (cwd[0] == '\0') {
1223                         printf("Could not get the current working directory - $PWD for an unknown reason.\n");
1224                 }
1225                 else {
1226                         /* uses the blend path relative to cwd important for loading relative linked files.
1227                          *
1228                          * cwd should contain c:\ etc on win32 so the relbase can be NULL
1229                          * relbase being NULL also prevents // being misunderstood as relative to the current
1230                          * blend file which isn't a feature we want to use in this case since were dealing
1231                          * with a path from the command line, rather than from inside Blender */
1232
1233                         char origpath[FILE_MAX];
1234                         BLI_strncpy(origpath, path, FILE_MAX);
1235                         
1236                         BLI_make_file_string(NULL, path, cwd, origpath); 
1237                 }
1238         }
1239         
1240         return wasrelative;
1241 }
1242
1243 #ifdef _WIN32
1244 /**
1245  * Tries appending each of the semicolon-separated extensions in the PATHEXT
1246  * environment variable (Windows-only) onto *name in turn until such a file is found.
1247  * Returns success/failure.
1248  */
1249 bool BLI_path_program_extensions_add_win32(char *name, const size_t maxlen)
1250 {
1251         bool retval = false;
1252         int type;
1253
1254         type = BLI_exists(name);
1255         if ((type == 0) || S_ISDIR(type)) {
1256                 /* typically 3-5, ".EXE", ".BAT"... etc */
1257                 const int ext_max = 12;
1258                 const char *ext = getenv("PATHEXT");
1259                 if (ext) {
1260                         const int name_len = strlen(name);
1261                         char *filename = alloca(name_len + ext_max);
1262                         char *filename_ext;
1263                         const char *ext_next;
1264
1265                         /* null terminated in the loop */
1266                         memcpy(filename, name, name_len);
1267                         filename_ext = filename + name_len;
1268
1269                         do {
1270                                 int ext_len;
1271                                 ext_next = strchr(ext, ';');
1272                                 ext_len = ext_next ? ((ext_next++) - ext) : strlen(ext);
1273
1274                                 if (LIKELY(ext_len < ext_max)) {
1275                                         memcpy(filename_ext, ext, ext_len);
1276                                         filename_ext[ext_len] = '\0';
1277
1278                                         type = BLI_exists(filename);
1279                                         if (type && (!S_ISDIR(type))) {
1280                                                 retval = true;
1281                                                 BLI_strncpy(name, filename, maxlen);
1282                                                 break;
1283                                         }
1284                                 }
1285                         } while ((ext = ext_next));
1286                 }
1287         }
1288         else {
1289                 retval = true;
1290         }
1291
1292         return retval;
1293 }
1294 #endif  /* WIN32 */
1295
1296 /**
1297  * Search for a binary (executable)
1298  */
1299 bool BLI_path_program_search(
1300         char *fullname, const size_t maxlen,
1301         const char *name)
1302 {
1303         const char *path;
1304         bool retval = false;
1305
1306 #ifdef _WIN32
1307         const char separator = ';';
1308 #else
1309         const char separator = ':';
1310 #endif
1311
1312         path = getenv("PATH");
1313         if (path) {
1314                 char filename[FILE_MAX];
1315                 const char *temp;
1316
1317                 do {
1318                         temp = strchr(path, separator);
1319                         if (temp) {
1320                                 strncpy(filename, path, temp - path);
1321                                 filename[temp - path] = 0;
1322                                 path = temp + 1;
1323                         }
1324                         else {
1325                                 strncpy(filename, path, sizeof(filename));
1326                         }
1327
1328                         BLI_path_append(filename, maxlen, name);
1329                         if (
1330 #ifdef _WIN32
1331                             BLI_path_program_extensions_add_win32(filename, maxlen)
1332 #else
1333                             BLI_exists(filename)
1334 #endif
1335                             )
1336                         {
1337                                 BLI_strncpy(fullname, filename, maxlen);
1338                                 retval = true;
1339                                 break;
1340                         }
1341                 } while (temp);
1342         }
1343
1344         if (retval == false) {
1345                 *fullname = '\0';
1346         }
1347
1348         return retval;
1349 }
1350
1351 /**
1352  * Copies into *last the part of *dir following the second-last slash.
1353  */
1354 void BLI_getlastdir(const char *dir, char *last, const size_t maxlen)
1355 {
1356         const char *s = dir;
1357         const char *lslash = NULL;
1358         const char *prevslash = NULL;
1359         while (*s) {
1360                 if ((*s == '\\') || (*s == '/')) {
1361                         prevslash = lslash;
1362                         lslash = s;
1363                 }
1364                 s++;
1365         }
1366         if (prevslash) {
1367                 BLI_strncpy(last, prevslash + 1, maxlen);
1368         }
1369         else {
1370                 BLI_strncpy(last, dir, maxlen);
1371         }
1372 }
1373
1374
1375 /**
1376  * Sets the specified environment variable to the specified value,
1377  * and clears it if val == NULL.
1378  */
1379 void BLI_setenv(const char *env, const char *val)
1380 {
1381         /* free windows */
1382 #if (defined(WIN32) || defined(WIN64)) && defined(FREE_WINDOWS)
1383         char *envstr;
1384
1385         if (val)
1386                 envstr = BLI_sprintfN("%s=%s", env, val);
1387         else
1388                 envstr = BLI_sprintfN("%s=", env);
1389
1390         putenv(envstr);
1391         MEM_freeN(envstr);
1392
1393         /* non-free windows */
1394 #elif (defined(WIN32) || defined(WIN64)) /* not free windows */
1395         uputenv(env, val);
1396
1397
1398 #else
1399         /* linux/osx/bsd */
1400         if (val)
1401                 setenv(env, val, 1);
1402         else
1403                 unsetenv(env);
1404 #endif
1405 }
1406
1407
1408 /**
1409  * Only set an env var if already not there.
1410  * Like Unix setenv(env, val, 0);
1411  *
1412  * (not used anywhere).
1413  */
1414 void BLI_setenv_if_new(const char *env, const char *val)
1415 {
1416         if (getenv(env) == NULL)
1417                 BLI_setenv(env, val);
1418 }
1419
1420 /**
1421  * Strips off nonexistent (or non-accessible) subdirectories from the end of *dir, leaving the path of
1422  * the lowest-level directory that does exist and we can read.
1423  */
1424 void BLI_make_exist(char *dir)
1425 {
1426         bool valid_path = true;
1427
1428         /* Loop as long as cur path is not a dir, and we can get a parent path. */
1429         while ((BLI_access(dir, R_OK) != 0) && (valid_path = BLI_parent_dir(dir)));
1430
1431         /* If we could not find an existing dir, use default root... */
1432         if (!valid_path || !dir[0]) {
1433 #ifdef WIN32
1434                 get_default_root(dir);
1435 #else
1436                 strcpy(dir, "/");
1437 #endif
1438         }
1439 }
1440
1441 /**
1442  * Ensures that the parent directory of *name exists.
1443  */
1444 void BLI_make_existing_file(const char *name)
1445 {
1446         char di[FILE_MAX];
1447         BLI_split_dir_part(name, di, sizeof(di));
1448
1449         /* make if the dir doesn't exist */
1450         BLI_dir_create_recursive(di);
1451 }
1452
1453 /**
1454  * Returns in *string the concatenation of *dir and *file (also with *relabase on the
1455  * front if specified and *dir begins with "//"). Normalizes all occurrences of path
1456  * separators, including ensuring there is exactly one between the copies of *dir and *file,
1457  * and between the copies of *relabase and *dir.
1458  *
1459  * \param relabase  Optional prefix to substitute for "//" on front of *dir
1460  * \param string  Area to return result
1461  */
1462 void BLI_make_file_string(const char *relabase, char *string, const char *dir, const char *file)
1463 {
1464         int sl;
1465
1466         if (string) {
1467                 /* ensure this is always set even if dir/file are NULL */
1468                 string[0] = '\0';
1469
1470                 if (ELEM(NULL, dir, file)) {
1471                         return; /* We don't want any NULLs */
1472                 }
1473         }
1474         else {
1475                 return; /* string is NULL, probably shouldnt happen but return anyway */
1476         }
1477
1478
1479         /* we first push all slashes into unix mode, just to make sure we don't get
1480          * any mess with slashes later on. -jesterKing */
1481         /* constant strings can be passed for those parameters - don't change them - elubie */
1482 #if 0
1483         BLI_str_replace_char(relabase, '\\', '/');
1484         BLI_str_replace_char(dir, '\\', '/');
1485         BLI_str_replace_char(file, '\\', '/');
1486 #endif
1487
1488         /* Resolve relative references */
1489         if (relabase && dir[0] == '/' && dir[1] == '/') {
1490                 char *lslash;
1491                 
1492                 /* Get the file name, chop everything past the last slash (ie. the filename) */
1493                 strcpy(string, relabase);
1494                 
1495                 lslash = (char *)BLI_last_slash(string);
1496                 if (lslash) *(lslash + 1) = 0;
1497
1498                 dir += 2; /* Skip over the relative reference */
1499         }
1500 #ifdef WIN32
1501         else {
1502                 if (BLI_strnlen(dir, 3) >= 2 && dir[1] == ':') {
1503                         BLI_strncpy(string, dir, 3);
1504                         dir += 2;
1505                 }
1506                 else if (BLI_strnlen(dir, 3) >= 2 && BLI_path_is_unc(dir)) {
1507                         string[0] = 0;
1508                 }
1509                 else { /* no drive specified */
1510                            /* first option: get the drive from the relabase if it has one */
1511                         if (relabase && BLI_strnlen(relabase, 3) >= 2 && relabase[1] == ':') {
1512                                 BLI_strncpy(string, relabase, 3);
1513                                 string[2] = '\\';
1514                                 string[3] = '\0';
1515                         }
1516                         else { /* we're out of luck here, guessing the first valid drive, usually c:\ */
1517                                 get_default_root(string);
1518                         }
1519                         
1520                         /* ignore leading slashes */
1521                         while (*dir == '/' || *dir == '\\') dir++;
1522                 }
1523         }
1524 #endif
1525
1526         strcat(string, dir);
1527
1528         /* Make sure string ends in one (and only one) slash */
1529         /* first trim all slashes from the end of the string */
1530         sl = strlen(string);
1531         while (sl > 0 && (string[sl - 1] == '/' || string[sl - 1] == '\\') ) {
1532                 string[sl - 1] = '\0';
1533                 sl--;
1534         }
1535         /* since we've now removed all slashes, put back one slash at the end. */
1536         strcat(string, "/");
1537         
1538         while (*file && (*file == '/' || *file == '\\')) /* Trim slashes from the front of file */
1539                 file++;
1540                 
1541         strcat(string, file);
1542         
1543         /* Push all slashes to the system preferred direction */
1544         BLI_path_native_slash(string);
1545 }
1546
1547 static bool testextensie_ex(const char *str, const size_t str_len,
1548                             const char *ext, const size_t ext_len)
1549 {
1550         BLI_assert(strlen(str) == str_len);
1551         BLI_assert(strlen(ext) == ext_len);
1552
1553         return  (((str_len == 0 || ext_len == 0 || ext_len >= str_len) == 0) &&
1554                  (BLI_strcasecmp(ext, str + str_len - ext_len) == 0));
1555 }
1556
1557 /* does str end with ext. */
1558 bool BLI_testextensie(const char *str, const char *ext)
1559 {
1560         return testextensie_ex(str, strlen(str), ext, strlen(ext));
1561 }
1562
1563 bool BLI_testextensie_n(const char *str, ...)
1564 {
1565         const size_t str_len = strlen(str);
1566
1567         va_list args;
1568         const char *ext;
1569         bool ret = false;
1570
1571         va_start(args, str);
1572
1573         while ((ext = (const char *) va_arg(args, void *))) {
1574                 if (testextensie_ex(str, str_len, ext, strlen(ext))) {
1575                         ret = true;
1576                         break;
1577                 }
1578         }
1579
1580         va_end(args);
1581
1582         return ret;
1583 }
1584
1585 /* does str end with any of the suffixes in *ext_array. */
1586 bool BLI_testextensie_array(const char *str, const char **ext_array)
1587 {
1588         const size_t str_len = strlen(str);
1589         int i = 0;
1590
1591         while (ext_array[i]) {
1592                 if (testextensie_ex(str, str_len, ext_array[i], strlen(ext_array[i]))) {
1593                         return true;
1594                 }
1595
1596                 i++;
1597         }
1598         return false;
1599 }
1600
1601 /**
1602  * Semicolon separated wildcards, eg:
1603  *  '*.zip;*.py;*.exe'
1604  * does str match any of the semicolon-separated glob patterns in fnmatch.
1605  */
1606 bool BLI_testextensie_glob(const char *str, const char *ext_fnmatch)
1607 {
1608         const char *ext_step = ext_fnmatch;
1609         char pattern[16];
1610
1611         while (ext_step[0]) {
1612                 const char *ext_next;
1613                 size_t len_ext;
1614
1615                 if ((ext_next = strchr(ext_step, ';'))) {
1616                         len_ext = ext_next - ext_step + 1;
1617                         BLI_strncpy(pattern, ext_step, (len_ext > sizeof(pattern)) ? sizeof(pattern) : len_ext);
1618                 }
1619                 else {
1620                         len_ext = BLI_strncpy_rlen(pattern, ext_step, sizeof(pattern));
1621                 }
1622
1623                 if (fnmatch(pattern, str, FNM_CASEFOLD) == 0) {
1624                         return true;
1625                 }
1626                 ext_step += len_ext;
1627         }
1628
1629         return false;
1630 }
1631
1632
1633 /**
1634  * Removes any existing extension on the end of \a path and appends \a ext.
1635  * \return false if there was no room.
1636  */
1637 bool BLI_replace_extension(char *path, size_t maxlen, const char *ext)
1638 {
1639         const size_t path_len = strlen(path);
1640         const size_t ext_len = strlen(ext);
1641         ssize_t a;
1642
1643         for (a = path_len - 1; a >= 0; a--) {
1644                 if (ELEM(path[a], '.', '/', '\\')) {
1645                         break;
1646                 }
1647         }
1648
1649         if ((a < 0) || (path[a] != '.')) {
1650                 a = path_len;
1651         }
1652
1653         if (a + ext_len >= maxlen)
1654                 return false;
1655
1656         memcpy(path + a, ext, ext_len + 1);
1657         return true;
1658 }
1659
1660 /**
1661  * Strip's trailing '.'s and adds the extension only when needed
1662  */
1663 bool BLI_ensure_extension(char *path, size_t maxlen, const char *ext)
1664 {
1665         const size_t path_len = strlen(path);
1666         const size_t ext_len = strlen(ext);
1667         ssize_t a;
1668
1669         /* first check the extension is already there */
1670         if ((ext_len <= path_len) && (STREQ(path + (path_len - ext_len), ext))) {
1671                 return true;
1672         }
1673
1674         for (a = path_len - 1; a >= 0; a--) {
1675                 if (path[a] == '.') {
1676                         path[a] = '\0';
1677                 }
1678                 else {
1679                         break;
1680                 }
1681         }
1682         a++;
1683
1684         if (a + ext_len >= maxlen)
1685                 return false;
1686
1687         memcpy(path + a, ext, ext_len + 1);
1688         return true;
1689 }
1690
1691 bool BLI_ensure_filename(char *filepath, size_t maxlen, const char *filename)
1692 {
1693         char *c = (char *)BLI_last_slash(filepath);
1694         if (!c || ((c - filepath) < maxlen - (strlen(filename) + 1))) {
1695                 strcpy(c ? &c[1] : filepath, filename);
1696                 return true;
1697         }
1698         return false;
1699 }
1700
1701 /* Converts "/foo/bar.txt" to "/foo/" and "bar.txt"
1702  * - wont change 'string'
1703  * - wont create any directories
1704  * - dosnt use CWD, or deal with relative paths.
1705  * - Only fill's in *dir and *file when they are non NULL
1706  * */
1707 void BLI_split_dirfile(const char *string, char *dir, char *file, const size_t dirlen, const size_t filelen)
1708 {
1709         const char *lslash_str = BLI_last_slash(string);
1710         const size_t lslash = lslash_str ? (size_t)(lslash_str - string) + 1 : 0;
1711
1712         if (dir) {
1713                 if (lslash) {
1714                         BLI_strncpy(dir, string, MIN2(dirlen, lslash + 1)); /* +1 to include the slash and the last char */
1715                 }
1716                 else {
1717                         dir[0] = '\0';
1718                 }
1719         }
1720         
1721         if (file) {
1722                 BLI_strncpy(file, string + lslash, filelen);
1723         }
1724 }
1725
1726 /**
1727  * Copies the parent directory part of string into *dir, max length dirlen.
1728  */
1729 void BLI_split_dir_part(const char *string, char *dir, const size_t dirlen)
1730 {
1731         BLI_split_dirfile(string, dir, NULL, dirlen, 0);
1732 }
1733
1734 /**
1735  * Copies the leaf filename part of string into *file, max length filelen.
1736  */
1737 void BLI_split_file_part(const char *string, char *file, const size_t filelen)
1738 {
1739         BLI_split_dirfile(string, NULL, file, 0, filelen);
1740 }
1741
1742 /**
1743  * Append a filename to a dir, ensuring slash separates.
1744  */
1745 void BLI_path_append(char *__restrict dst, const size_t maxlen, const char *__restrict file)
1746 {
1747         size_t dirlen = BLI_strnlen(dst, maxlen);
1748
1749         /* inline BLI_add_slash */
1750         if ((dirlen > 0) && (dst[dirlen - 1] != SEP)) {
1751                 dst[dirlen++] = SEP;
1752                 dst[dirlen] = '\0';
1753         }
1754
1755         if (dirlen >= maxlen) {
1756                 return; /* fills the path */
1757         }
1758
1759         BLI_strncpy(dst + dirlen, file, maxlen - dirlen);
1760 }
1761
1762 /**
1763  * Simple appending of filename to dir, does not check for valid path!
1764  * Puts result into *dst, which may be same area as *dir.
1765  */
1766 void BLI_join_dirfile(char *__restrict dst, const size_t maxlen, const char *__restrict dir, const char *__restrict file)
1767 {
1768         size_t dirlen = BLI_strnlen(dir, maxlen);
1769
1770         /* args can't match */
1771         BLI_assert(!ELEM(dst, dir, file));
1772
1773         if (dirlen == maxlen) {
1774                 memcpy(dst, dir, dirlen);
1775                 dst[dirlen - 1] = '\0';
1776                 return; /* dir fills the path */
1777         }
1778         else {
1779                 memcpy(dst, dir, dirlen + 1);
1780         }
1781
1782         if (dirlen + 1 >= maxlen) {
1783                 return; /* fills the path */
1784         }
1785
1786         /* inline BLI_add_slash */
1787         if ((dirlen > 0) && (dst[dirlen - 1] != SEP)) {
1788                 dst[dirlen++] = SEP;
1789                 dst[dirlen] = '\0';
1790         }
1791
1792         if (dirlen >= maxlen) {
1793                 return; /* fills the path */
1794         }
1795
1796         BLI_strncpy(dst + dirlen, file, maxlen - dirlen);
1797 }
1798
1799 /**
1800  * like pythons os.path.basename()
1801  *
1802  * \return The pointer into \a path string immediately after last slash,
1803  * or start of \a path if none found.
1804  */
1805 const char *BLI_path_basename(const char *path)
1806 {
1807         const char * const filename = BLI_last_slash(path);
1808         return filename ? filename + 1 : path;
1809 }
1810
1811 /* UNUSED */
1812 #if 0
1813 /**
1814  * Produce image export path.
1815  * 
1816  * Returns:
1817  * 0        if image filename is empty or if destination path
1818  *          matches image path (i.e. both are the same file).
1819  * 2        if source is identical to destination.
1820  * 1        if rebase was successful
1821  * -------------------------------------------------------------
1822  * Hint: Trailing slash in dest_dir is optional.
1823  *
1824  * Logic:
1825  *
1826  * - if an image is "below" current .blend file directory:
1827  *   rebuild the same dir structure in dest_dir
1828  *
1829  *   Example: 
1830  *   src : //textures/foo/bar.png
1831  *   dest: [dest_dir]/textures/foo/bar.png.
1832  *
1833  * - if an image is not "below" current .blend file directory,
1834  *   disregard it's path and copy it into the destination  
1835  *   directory.
1836  *
1837  *   Example:
1838  *   src : //../foo/bar.png becomes
1839  *   dest: [dest_dir]/bar.png.
1840  *
1841  * This logic ensures that all image paths are relative and
1842  * that a user gets his images in one place. It'll also provide
1843  * consistent behavior across exporters.
1844  * IMPORTANT NOTE: If base_dir contains an empty string, then
1845  * this function returns wrong results!
1846  * XXX: test on empty base_dir and return an error ?
1847  */
1848
1849 /**
1850  *
1851  * \param abs  Optional string to return new full path
1852  * \param abs_len  Size of *abs string
1853  * \param rel  Optional area to return new path relative to parent directory of .blend file
1854  *             (only meaningful if item is in a subdirectory thereof)
1855  * \param rel_len  Size of *rel area
1856  * \param base_dir  Path of .blend file
1857  * \param src_dir  Original path of item (any initial "//" will be expanded to
1858  *                 parent directory of .blend file)
1859  * \param dest_dir  New directory into which item will be moved
1860  * \return bli_rebase_state
1861  *
1862  * \note Not actually used anywhere!
1863  */
1864 int BLI_rebase_path(char *abs, size_t abs_len,
1865                     char *rel, size_t rel_len,
1866                     const char *base_dir, const char *src_dir, const char *dest_dir)
1867 {
1868         char path[FILE_MAX];  /* original full path of item */
1869         char dir[FILE_MAX];   /* directory part of src_dir */
1870         char base[FILE_MAX];  /* basename part of src_dir */
1871         char blend_dir[FILE_MAX];   /* directory, where current .blend file resides */
1872         char dest_path[FILE_MAX];
1873         char rel_dir[FILE_MAX];
1874         int len;
1875
1876         if (abs)
1877                 abs[0] = 0;
1878
1879         if (rel)
1880                 rel[0] = 0;
1881
1882         BLI_split_dir_part(base_dir, blend_dir, sizeof(blend_dir));
1883
1884         if (src_dir[0] == '\0')
1885                 return BLI_REBASE_NO_SRCDIR;
1886
1887         BLI_strncpy(path, src_dir, sizeof(path));
1888
1889         /* expand "//" in filename and get absolute path */
1890         BLI_path_abs(path, base_dir);
1891
1892         /* get the directory part */
1893         BLI_split_dirfile(path, dir, base, sizeof(dir), sizeof(base));
1894
1895         len = strlen(blend_dir);
1896
1897         rel_dir[0] = 0;
1898
1899         /* if image is "below" current .blend file directory */
1900         if (!BLI_path_ncmp(path, blend_dir, len)) {
1901
1902                 if (BLI_path_cmp(dir, blend_dir) == 0) {
1903                         /* image is directly in .blend file parent directory => put directly in dest_dir */
1904                         BLI_join_dirfile(dest_path, sizeof(dest_path), dest_dir, base);
1905                 }
1906                 else {
1907                         /* "below" (in subdirectory of .blend file parent directory) => put in same relative directory structure in dest_dir */
1908                         /* rel = image_path_dir - blend_dir */
1909                         BLI_strncpy(rel_dir, dir + len, sizeof(rel_dir));
1910                         /* subdirectories relative to blend_dir */
1911                         BLI_join_dirfile(dest_path, sizeof(dest_path), dest_dir, rel_dir);
1912                         /* same subdirectories relative to dest_dir */
1913                         BLI_path_append(dest_path, sizeof(dest_path), base);
1914                         /* keeping original item basename */
1915                 }
1916
1917         }
1918         /* image is out of current directory -- just put straight in dest_dir */
1919         else {
1920                 BLI_join_dirfile(dest_path, sizeof(dest_path), dest_dir, base);
1921         }
1922
1923         if (abs)
1924                 BLI_strncpy(abs, dest_path, abs_len);
1925
1926         if (rel) {
1927                 strncat(rel, rel_dir, rel_len);
1928                 strncat(rel, base, rel_len); /* FIXME: could overflow rel area! */
1929         }
1930
1931         /* return 2 if (src == dest) */
1932         if (BLI_path_cmp(path, dest_path) == 0) {
1933                 // if (G.debug & G_DEBUG) printf("%s and %s are the same file\n", path, dest_path);
1934                 return BLI_REBASE_IDENTITY;
1935         }
1936
1937         return BLI_REBASE_OK;
1938 }
1939 #endif
1940
1941
1942 /**
1943  * Returns pointer to the leftmost path separator in string. Not actually used anywhere.
1944  */
1945 const char *BLI_first_slash(const char *string)
1946 {
1947         const char * const ffslash = strchr(string, '/');
1948         const char * const fbslash = strchr(string, '\\');
1949         
1950         if (!ffslash) return fbslash;
1951         else if (!fbslash) return ffslash;
1952         
1953         if ((intptr_t)ffslash < (intptr_t)fbslash) return ffslash;
1954         else return fbslash;
1955 }
1956
1957 /**
1958  * Returns pointer to the rightmost path separator in string.
1959  */
1960 const char *BLI_last_slash(const char *string)
1961 {
1962         const char * const lfslash = strrchr(string, '/');
1963         const char * const lbslash = strrchr(string, '\\');
1964
1965         if (!lfslash) return lbslash; 
1966         else if (!lbslash) return lfslash;
1967         
1968         if ((intptr_t)lfslash < (intptr_t)lbslash) return lbslash;
1969         else return lfslash;
1970 }
1971
1972 /**
1973  * Appends a slash to string if there isn't one there already.
1974  * Returns the new length of the string.
1975  */
1976 int BLI_add_slash(char *string)
1977 {
1978         int len = strlen(string);
1979         if (len == 0 || string[len - 1] != SEP) {
1980                 string[len] = SEP;
1981                 string[len + 1] = '\0';
1982                 return len + 1;
1983         }
1984         return len;
1985 }
1986
1987 /**
1988  * Removes the last slash and everything after it to the end of string, if there is one.
1989  */
1990 void BLI_del_slash(char *string)
1991 {
1992         int len = strlen(string);
1993         while (len) {
1994                 if (string[len - 1] == SEP) {
1995                         string[len - 1] = '\0';
1996                         len--;
1997                 }
1998                 else {
1999                         break;
2000                 }
2001         }
2002 }
2003
2004 /**
2005  * Changes to the path separators to the native ones for this OS.
2006  */
2007 void BLI_path_native_slash(char *path)
2008 {
2009 #ifdef WIN32
2010         if (path && BLI_strnlen(path, 3) > 2) {
2011                 BLI_str_replace_char(path + 2, '/', '\\');
2012         }
2013 #else
2014         BLI_str_replace_char(path + BLI_path_unc_prefix_len(path), '\\', '/');
2015 #endif
2016 }
2017
2018
2019 #ifdef WITH_ICONV
2020
2021 /**
2022  * Converts a string encoded in the charset named by *code to UTF-8.
2023  * Opens a new iconv context each time it is run, which is probably not the
2024  * most efficient. */
2025 void BLI_string_to_utf8(char *original, char *utf_8, const char *code)
2026 {
2027         size_t inbytesleft = strlen(original);
2028         size_t outbytesleft = 512;
2029         size_t rv = 0;
2030         iconv_t cd;
2031         
2032         if (NULL == code) {
2033                 code = locale_charset();
2034         }
2035         cd = iconv_open("UTF-8", code);
2036
2037         if (cd == (iconv_t)(-1)) {
2038                 printf("iconv_open Error");
2039                 *utf_8 = '\0';
2040                 return;
2041         }
2042         rv = iconv(cd, &original, &inbytesleft, &utf_8, &outbytesleft);
2043         if (rv == (size_t) -1) {
2044                 printf("iconv Error\n");
2045                 iconv_close(cd);
2046                 return;
2047         }
2048         *utf_8 = '\0';
2049         iconv_close(cd);
2050 }
2051 #endif // WITH_ICONV