1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2020 - Raw Material Software Limited
6 
7    JUCE is an open source library subject to commercial or open-source
8    licensing.
9 
10    By using JUCE, you agree to the terms of both the JUCE 6 End-User License
11    Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
12 
13    End User License Agreement: www.juce.com/juce-6-licence
14    Privacy Policy: www.juce.com/juce-privacy-policy
15 
16    Or: You may also use this code under the terms of the GPL v3 (see
17    www.gnu.org/licenses).
18 
19    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
20    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
21    DISCLAIMED.
22 
23   ==============================================================================
24 */
25 
26 namespace juce
27 {
28 namespace build_tools
29 {
30     //==============================================================================
31     /** Manipulates a cross-platform partial file path. (Needed because File is designed
32         for absolute paths on the active OS)
33     */
34     class RelativePath
35     {
36     public:
37         //==============================================================================
38         enum RootFolder
39         {
40             unknown,
41             projectFolder,
42             buildTargetFolder
43         };
44 
45         //==============================================================================
RelativePath()46         RelativePath()
47             : root (unknown)
48         {}
49 
RelativePath(const String & relPath,const RootFolder rootType)50         RelativePath (const String& relPath, const RootFolder rootType)
51             : path (unixStylePath (relPath)), root (rootType)
52         {}
53 
RelativePath(const File & file,const File & rootFolder,const RootFolder rootType)54         RelativePath (const File& file, const File& rootFolder, const RootFolder rootType)
55             : path (unixStylePath (getRelativePathFrom (file, rootFolder))), root (rootType)
56         {}
57 
getRoot()58         RootFolder getRoot() const                              { return root; }
59 
toUnixStyle()60         String toUnixStyle() const                              { return unixStylePath (path); }
toWindowsStyle()61         String toWindowsStyle() const                           { return windowsStylePath (path); }
62 
getFileName()63         String getFileName() const                              { return getFakeFile().getFileName(); }
getFileNameWithoutExtension()64         String getFileNameWithoutExtension() const              { return getFakeFile().getFileNameWithoutExtension(); }
65 
getFileExtension()66         String getFileExtension() const                         { return getFakeFile().getFileExtension(); }
hasFileExtension(juce::StringRef extension)67         bool hasFileExtension (juce::StringRef extension) const { return getFakeFile().hasFileExtension (extension); }
isAbsolute()68         bool isAbsolute() const                                 { return isAbsolutePath (path); }
69 
withFileExtension(const String & extension)70         RelativePath withFileExtension (const String& extension) const
71         {
72             return RelativePath (path.upToLastOccurrenceOf (".", ! extension.startsWithChar ('.'), false) + extension, root);
73         }
74 
getParentDirectory()75         RelativePath getParentDirectory() const
76         {
77             String p (path);
78             if (path.endsWithChar ('/'))
79                 p = p.dropLastCharacters (1);
80 
81             return RelativePath (p.upToLastOccurrenceOf ("/", false, false), root);
82         }
83 
getChildFile(const String & subpath)84         RelativePath getChildFile (const String& subpath) const
85         {
86             if (isAbsolutePath (subpath))
87                 return RelativePath (subpath, root);
88 
89             String p (toUnixStyle());
90             if (! p.endsWithChar ('/'))
91                 p << '/';
92 
93             return RelativePath (p + subpath, root);
94         }
95 
rebased(const File & originalRoot,const File & newRoot,const RootFolder newRootType)96         RelativePath rebased (const File& originalRoot, const File& newRoot, const RootFolder newRootType) const
97         {
98             if (isAbsolute())
99                 return RelativePath (path, newRootType);
100 
101             return RelativePath (getRelativePathFrom (originalRoot.getChildFile (toUnixStyle()), newRoot), newRootType);
102         }
103 
104     private:
105         //==============================================================================
106         String path;
107         RootFolder root;
108 
getFakeFile()109         File getFakeFile() const
110         {
111            #if JUCE_WINDOWS
112             if (isAbsolutePath (path))
113             {
114                 // This is a hack to convert unix-style absolute paths into valid absolute Windows paths to avoid hitting
115                 // an assertion in File::parseAbsolutePath().
116                 if (path.startsWithChar (L'/') || path.startsWithChar (L'$') || path.startsWithChar (L'~'))
117                     return File (String ("C:\\") + windowsStylePath (path.substring (1)));
118 
119                 return File (path);
120             }
121            #endif
122 
123             // This method gets called very often, so we'll cache this directory.
124             static const File currentWorkingDirectory (File::getCurrentWorkingDirectory());
125             return currentWorkingDirectory.getChildFile (path);
126         }
127     };
128 }
129 }
130