Home > RAVEN > getFullPath.m

getFullPath

PURPOSE ^

getFullPath - Get absolute canonical path of a file or folder

SYNOPSIS ^

function File = getFullPath(File, Style)

DESCRIPTION ^

 getFullPath - Get absolute canonical path of a file or folder
 Absolute path names are safer than relative paths, when e.g. a GUI or TIMER
 callback changes the current directory. Only canonical paths without "." and
 ".." can be recognized uniquely.
 Long path names (>259 characters) require a magic initial key "\\?\" to be
 handled by Windows API functions, e.g. for Matlab's FOPEN, DIR and EXIST.

 FullName = getFullPath(Name, Style)
 INPUT:
   Name:  String or cell string, absolute or relative name of a file or
          folder. The path need not exist. Unicode strings, UNC paths and long
          names are supported.
   Style: Style of the output as string, optional, default: 'auto'.
          'auto': Add '\\?\' or '\\?\UNC\' for long names on demand.
          'lean': Magic string is not added.
          'fat':  Magic string is added for short names also.
          The Style is ignored when not running under Windows.

 OUTPUT:
   FullName: Absolute canonical path name as string or cell string.
          For empty strings the current directory is replied.
          '\\?\' or '\\?\UNC' is added on demand.

 NOTE: The M- and the MEX-version create the same results, the faster MEX
   function works under Windows only.
   Some functions of the Windows-API still do not support long file names.
   E.g. the Recycler and the Windows Explorer fail even with the magic '\\?\'
   prefix. Some functions of Matlab accept 260 characters (value of MAX_PATH),
   some at 259 already. Don't blame me.
   The 'fat' style is useful e.g. when Matlab's DIR command is called for a
   folder with les than 260 characters, but together with the file name this
   limit is exceeded. Then "dir(getFullPath([folder, '\*.*], 'fat'))" helps.

 EXAMPLES:
   cd(tempdir);                    % Assumed as 'C:\Temp' here
   getFullPath('File.Ext')         % 'C:\Temp\File.Ext'
   getFullPath('..\File.Ext')      % 'C:\File.Ext'
   getFullPath('..\..\File.Ext')   % 'C:\File.Ext'
   getFullPath('.\File.Ext')       % 'C:\Temp\File.Ext'
   getFullPath('*.txt')            % 'C:\Temp\*.txt'
   getFullPath('..')               % 'C:\'
   getFullPath('..\..\..')         % 'C:\'
   getFullPath('Folder\')          % 'C:\Temp\Folder\'
   getFullPath('D:\A\..\B')        % 'D:\B'
   getFullPath('\\Server\Folder\Sub\..\File.ext')
                                   % '\\Server\Folder\File.ext'
   getFullPath({'..', 'new'})      % {'C:\', 'C:\Temp\new'}
   getFullPath('.', 'fat')         % '\\?\C:\Temp\File.Ext'

 COMPILE:
   Automatic: InstallMex getFullPath.c uTest_getFullPath
   Manual:    mex -O getFullPath.c
   Download:  http://www.n-simon.de/mex
 Run the unit-test uTest_getFullPath after compiling.

 Tested: Matlab 6.5, 7.7, 7.8, 7.13, WinXP/32, Win7/64
         Compiler: LCC2.4/3.8, BCC5.5, OWC1.8, MSVC2008/2010
 Assumed Compatibility: higher Matlab versions
 Author: Jan Simon, Heidelberg, (C) 2009-2013 matlab.THISYEAR(a)nMINUSsimon.de

 See also: CD, FULLFILE, FILEPARTS.

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function File = getFullPath(File, Style)
0002 % getFullPath - Get absolute canonical path of a file or folder
0003 % Absolute path names are safer than relative paths, when e.g. a GUI or TIMER
0004 % callback changes the current directory. Only canonical paths without "." and
0005 % ".." can be recognized uniquely.
0006 % Long path names (>259 characters) require a magic initial key "\\?\" to be
0007 % handled by Windows API functions, e.g. for Matlab's FOPEN, DIR and EXIST.
0008 %
0009 % FullName = getFullPath(Name, Style)
0010 % INPUT:
0011 %   Name:  String or cell string, absolute or relative name of a file or
0012 %          folder. The path need not exist. Unicode strings, UNC paths and long
0013 %          names are supported.
0014 %   Style: Style of the output as string, optional, default: 'auto'.
0015 %          'auto': Add '\\?\' or '\\?\UNC\' for long names on demand.
0016 %          'lean': Magic string is not added.
0017 %          'fat':  Magic string is added for short names also.
0018 %          The Style is ignored when not running under Windows.
0019 %
0020 % OUTPUT:
0021 %   FullName: Absolute canonical path name as string or cell string.
0022 %          For empty strings the current directory is replied.
0023 %          '\\?\' or '\\?\UNC' is added on demand.
0024 %
0025 % NOTE: The M- and the MEX-version create the same results, the faster MEX
0026 %   function works under Windows only.
0027 %   Some functions of the Windows-API still do not support long file names.
0028 %   E.g. the Recycler and the Windows Explorer fail even with the magic '\\?\'
0029 %   prefix. Some functions of Matlab accept 260 characters (value of MAX_PATH),
0030 %   some at 259 already. Don't blame me.
0031 %   The 'fat' style is useful e.g. when Matlab's DIR command is called for a
0032 %   folder with les than 260 characters, but together with the file name this
0033 %   limit is exceeded. Then "dir(getFullPath([folder, '\*.*], 'fat'))" helps.
0034 %
0035 % EXAMPLES:
0036 %   cd(tempdir);                    % Assumed as 'C:\Temp' here
0037 %   getFullPath('File.Ext')         % 'C:\Temp\File.Ext'
0038 %   getFullPath('..\File.Ext')      % 'C:\File.Ext'
0039 %   getFullPath('..\..\File.Ext')   % 'C:\File.Ext'
0040 %   getFullPath('.\File.Ext')       % 'C:\Temp\File.Ext'
0041 %   getFullPath('*.txt')            % 'C:\Temp\*.txt'
0042 %   getFullPath('..')               % 'C:\'
0043 %   getFullPath('..\..\..')         % 'C:\'
0044 %   getFullPath('Folder\')          % 'C:\Temp\Folder\'
0045 %   getFullPath('D:\A\..\B')        % 'D:\B'
0046 %   getFullPath('\\Server\Folder\Sub\..\File.ext')
0047 %                                   % '\\Server\Folder\File.ext'
0048 %   getFullPath({'..', 'new'})      % {'C:\', 'C:\Temp\new'}
0049 %   getFullPath('.', 'fat')         % '\\?\C:\Temp\File.Ext'
0050 %
0051 % COMPILE:
0052 %   Automatic: InstallMex getFullPath.c uTest_getFullPath
0053 %   Manual:    mex -O getFullPath.c
0054 %   Download:  http://www.n-simon.de/mex
0055 % Run the unit-test uTest_getFullPath after compiling.
0056 %
0057 % Tested: Matlab 6.5, 7.7, 7.8, 7.13, WinXP/32, Win7/64
0058 %         Compiler: LCC2.4/3.8, BCC5.5, OWC1.8, MSVC2008/2010
0059 % Assumed Compatibility: higher Matlab versions
0060 % Author: Jan Simon, Heidelberg, (C) 2009-2013 matlab.THISYEAR(a)nMINUSsimon.de
0061 %
0062 % See also: CD, FULLFILE, FILEPARTS.
0063 
0064 % $JRev: R-G V:032 Sum:7Xd/JS0+yfax Date:15-Jan-2013 01:06:12 $
0065 % $License: BSD (use/copy/change/redistribute on own risk, mention the author) $
0066 % $UnitTest: uTest_getFullPath $
0067 % $File: Tools\GLFile\getFullPath.m $
0068 % History:
0069 % 001: 20-Apr-2010 22:28, Successor of Rel2AbsPath.
0070 % 010: 27-Jul-2008 21:59, Consider leading separator in M-version also.
0071 % 011: 24-Jan-2011 12:11, Cell strings, '~File' under linux.
0072 %      Check of input types in the M-version.
0073 % 015: 31-Mar-2011 10:48, BUGFIX: Accept [] as input as in the Mex version.
0074 %      Thanks to Jiro Doke, who found this bug by running the test function for
0075 %      the M-version.
0076 % 020: 18-Oct-2011 00:57, BUGFIX: Linux version created bad results.
0077 %      Thanks to Daniel.
0078 % 024: 10-Dec-2011 14:00, Care for long names under Windows in M-version.
0079 %      Improved the unittest function for Linux. Thanks to Paul Sexton.
0080 % 025: 09-Aug-2012 14:00, In MEX: Paths starting with "\\" can be non-UNC.
0081 %      The former version treated "\\?\C:\<longpath>\file" as UNC path and
0082 %      replied "\\?\UNC\?\C:\<longpath>\file".
0083 % 032: 12-Jan-2013 21:16, 'auto', 'lean' and 'fat' style.
0084 
0085 % Initialize: ==================================================================
0086 % Do the work: =================================================================
0087 
0088 % #############################################
0089 % ### USE THE MUCH FASTER MEX ON WINDOWS!!! ###
0090 % #############################################
0091 
0092 % Difference between M- and Mex-version:
0093 % - Mex does not work under MacOS/Unix.
0094 % - Mex calls Windows API function getFullPath.
0095 % - Mex is much faster.
0096 
0097 % Magix prefix for long Windows names:
0098 if nargin < 2
0099    Style = 'auto';
0100 end
0101 
0102 % Handle cell strings:
0103 % NOTE: It is faster to create a function @cell\getFullPath.m under Linux, but
0104 % under Windows this would shadow the fast C-Mex.
0105 if isa(File, 'cell')
0106    for iC = 1:numel(File)
0107       File{iC} = getFullPath(File{iC}, Style);
0108    end
0109    return;
0110 end
0111 
0112 % Check this once only:
0113 isWIN    = strncmpi(computer, 'PC', 2);
0114 MAX_PATH = 260;
0115 
0116 % Warn once per session (disable this under Linux/MacOS):
0117 persistent hasDataRead
0118 if isempty(hasDataRead)
0119    % Test this once only - there is no relation to the existence of DATAREAD!
0120    %if isWIN
0121    %   Show a warning, if the slower Matlab version is used - commented, because
0122    %   this is not a problem and it might be even useful when the MEX-folder is
0123    %   not inlcuded in the path yet.
0124    %   warning('JSimon:getFullPath:NoMex', ...
0125    %      ['getFullPath: Using slow Matlab-version instead of fast Mex.', ...
0126    %       char(10), 'Compile: InstallMex getFullPath.c']);
0127    %end
0128    
0129    % DATAREAD is deprecated in 2011b, but still available. In Matlab 6.5, REGEXP
0130    % does not know the 'split' command, therefore DATAREAD is preferred:
0131    hasDataRead = ~isempty(which('dataread'));
0132 end
0133 
0134 if isempty(File)  % Accept empty matrix as input:
0135    if ischar(File) || isnumeric(File)
0136       File = cd;
0137       return;
0138    else
0139       error(['JSimon:', mfilename, ':BadTypeInput1'], ...
0140          ['*** ', mfilename, ': Input must be a string or cell string']);
0141    end
0142 end
0143 
0144 if ischar(File) == 0  % Non-empty inputs must be strings
0145    error(['JSimon:', mfilename, ':BadTypeInput1'], ...
0146       ['*** ', mfilename, ': Input must be a string or cell string']);
0147 end
0148 
0149 if isWIN  % Windows: --------------------------------------------------------
0150    FSep = '\';
0151    File = strrep(File, '/', FSep);
0152    
0153    % Remove the magic key on demand, it is appended finally again:
0154    if strncmp(File, '\\?\', 4)
0155       if strncmpi(File, '\\?\UNC\', 8)
0156          File = ['\', File(7:length(File))];  % Two leading backslashes!
0157       else
0158          File = File(5:length(File));
0159       end
0160    end
0161    
0162    isUNC   = strncmp(File, '\\', 2);
0163    FileLen = length(File);
0164    if isUNC == 0                        % File is not a UNC path
0165       % Leading file separator means relative to current drive or base folder:
0166       ThePath = cd;
0167       if File(1) == FSep
0168          if strncmp(ThePath, '\\', 2)   % Current directory is a UNC path
0169             sepInd  = strfind(ThePath, '\');
0170             ThePath = ThePath(1:sepInd(4));
0171          else
0172             ThePath = ThePath(1:3);     % Drive letter only
0173          end
0174       end
0175       
0176       if FileLen < 2 || File(2) ~= ':'  % Does not start with drive letter
0177          if ThePath(length(ThePath)) ~= FSep
0178             if File(1) ~= FSep
0179                File = [ThePath, FSep, File];
0180             else                        % File starts with separator:
0181                File = [ThePath, File];
0182             end
0183          else                           % Current path ends with separator:
0184             if File(1) ~= FSep
0185                File = [ThePath, File];
0186             else                        % File starts with separator:
0187                ThePath(length(ThePath)) = [];
0188                File = [ThePath, File];
0189             end
0190          end
0191          
0192       elseif FileLen == 2 && File(2) == ':'   % "C:" current directory on C!
0193          % "C:" is the current directory on the C-disk, even if the current
0194          % directory is on another disk! This was ignored in Matlab 6.5, but
0195          % modern versions considers this strange behaviour.
0196          if strncmpi(ThePath, File, 2)
0197             File = ThePath;
0198          else
0199             try
0200                File = cd(cd(File));
0201             catch    % No MException to support Matlab6.5...
0202                if exist(File, 'dir')  % No idea what could cause an error then!
0203                   rethrow(lasterror);
0204                else  % Reply "K:\" for not existing disk:
0205                   File = [File, FSep];
0206                end
0207             end
0208          end
0209       end
0210    end
0211    
0212 else         % Linux, MacOS: ---------------------------------------------------
0213    FSep = '/';
0214    File = strrep(File, '\', FSep);
0215    
0216    if strcmp(File, '~') || strncmp(File, '~/', 2)  % Home directory:
0217       HomeDir = getenv('HOME');
0218       if ~isempty(HomeDir)
0219          File(1) = [];
0220          File    = [HomeDir, File];
0221       end
0222       
0223    elseif strncmpi(File, FSep, 1) == 0
0224       % Append relative path to current folder:
0225       ThePath = cd;
0226       if ThePath(length(ThePath)) == FSep
0227          File = [ThePath, File];
0228       else
0229          File = [ThePath, FSep, File];
0230       end
0231    end
0232 end
0233 
0234 % Care for "\." and "\.." - no efficient algorithm, but the fast Mex is
0235 % recommended at all!
0236 if ~isempty(strfind(File, [FSep, '.']))
0237    if isWIN
0238       if strncmp(File, '\\', 2)  % UNC path
0239          index = strfind(File, '\');
0240          if length(index) < 4    % UNC path without separator after the folder:
0241             return;
0242          end
0243          Drive            = File(1:index(4));
0244          File(1:index(4)) = [];
0245       else
0246          Drive     = File(1:3);
0247          File(1:3) = [];
0248       end
0249    else  % Unix, MacOS:
0250       isUNC   = false;
0251       Drive   = FSep;
0252       File(1) = [];
0253    end
0254    
0255    hasTrailFSep = (File(length(File)) == FSep);
0256    if hasTrailFSep
0257       File(length(File)) = [];
0258    end
0259    
0260    if hasDataRead
0261       if isWIN  % Need "\\" as separator:
0262          C = dataread('string', File, '%s', 'delimiter', '\\');  %#ok<REMFF1>
0263       else
0264          C = dataread('string', File, '%s', 'delimiter', FSep);  %#ok<REMFF1>
0265       end
0266    else  % Use the slower REGEXP, when DATAREAD is not available anymore:
0267       C = regexp(File, FSep, 'split');
0268    end
0269    
0270    % Remove '\.\' directly without side effects:
0271    C(strcmp(C, '.')) = [];
0272    
0273    % Remove '\..' with the parent recursively:
0274    R = 1:length(C);
0275    for dd = reshape(find(strcmp(C, '..')), 1, [])
0276       index    = find(R == dd);
0277       R(index) = [];
0278       if index > 1
0279          R(index - 1) = [];
0280       end
0281    end
0282    
0283    if isempty(R)
0284       File = Drive;
0285       if isUNC && ~hasTrailFSep
0286          File(length(File)) = [];
0287       end
0288       
0289    elseif isWIN
0290       % If you have CStr2String, use the faster:
0291       %   File = CStr2String(C(R), FSep, hasTrailFSep);
0292       File = sprintf('%s\\', C{R});
0293       if hasTrailFSep
0294          File = [Drive, File];
0295       else
0296          File = [Drive, File(1:length(File) - 1)];
0297       end
0298       
0299    else  % Unix:
0300       File = [Drive, sprintf('%s/', C{R})];
0301       if ~hasTrailFSep
0302          File(length(File)) = [];
0303       end
0304    end
0305 end
0306 
0307 % "Very" long names under Windows:
0308 if isWIN
0309    if ~ischar(Style)
0310       error(['JSimon:', mfilename, ':BadTypeInput2'], ...
0311          ['*** ', mfilename, ': Input must be a string or cell string']);
0312    end
0313    
0314    if (strncmpi(Style, 'a', 1) && length(File) >= MAX_PATH) || ...
0315          strncmpi(Style, 'f', 1)
0316       % Do not use [isUNC] here, because this concerns the input, which can
0317       % '.\File', while the current directory is an UNC path.
0318       if strncmp(File, '\\', 2)  % UNC path
0319          File = ['\\?\UNC', File(2:end)];
0320       else
0321          File = ['\\?\', File];
0322       end
0323    end
0324 end
0325 
0326 % return;

Generated on Mon 06-Jan-2014 14:58:12 by m2html © 2005