1 // Copyright Ferdinand Majeatabase/D/rech 2011 - 2012. 2 // Distributed under the Boost Software License, Version 1.0. 3 // (See accompanying file LICENSE_1_0.txt or copy at 4 // http://www.boost.org/LICENSE_1_0.txt) 5 6 7 // Utility functions used by D:GameVFS. 8 module dgamevfs.util; 9 10 11 import std.algorithm; 12 import std.array; 13 import std.path; 14 15 import dgamevfs.exceptions; 16 17 18 // Is a file/directory name valid (i.e. no directory or package separators)? 19 bool noSeparators(string name) @trusted pure nothrow @nogc 20 { 21 return !name.canFind("/") && !name.canFind("::"); 22 } 23 24 // Are there no package separators in the path? 25 bool noPackageSeparators(string path) @trusted pure nothrow @nogc 26 { 27 return !path.canFind("::"); 28 } 29 30 // Clean any leading "./" and trailing "/" from a filesystem path, and replace "\" by "/". 31 string cleanFSPath(string path) @trusted pure nothrow 32 { 33 while(path.startsWith("./")) { path = path[2 .. $]; } 34 while(path.endsWith("/")) { path = path[0 .. $ - 1]; } 35 return path.replace("\\", "/"); 36 } 37 38 /* 39 * If a path starts by a package, return it. 40 * 41 * Params: path = Path to parse. 42 * rest = Rest of the path (beyond the package separator) 43 * will be written here if the path starts by a package. 44 * Otherwise this will be empty. 45 * 46 * Returns: Package the path starts with, if any. null otherwise. 47 */ 48 string expectPackage(string path, out string rest) @trusted pure nothrow @nogc 49 { 50 auto parts = path.findSplit("::"); 51 // No package separator. 52 if(parts[2].length == 0) { return null; } 53 // Package separator, but in a subdir. 54 if(parts[0].canFind("/")) { return null; } 55 56 rest = parts[2]; 57 return parts[0]; 58 } 59 60 /* 61 * If a path starts by a subdirectory, return it. 62 * 63 * Params: path = Path to parse. 64 * rest = Rest of the path (beyond the directory separator) 65 * will be written here if the path starts by a subdirectory. 66 * Otherwise this will be empty. 67 * 68 * Returns: Subdirectory the path starts with, if any. null otherwise. 69 * 70 * Throws: VFSInvalidPathException if a package separator is found in the directory name. 71 */ 72 string expectSubdir(string path, out string rest) @trusted pure 73 { 74 auto parts = path.findSplit("/"); 75 // No directory separator. 76 if(parts[2].length == 0) { return null; } 77 // Package separator in a directory name. 78 if(parts[0].canFind("::")) 79 { 80 throw invalidPath("Unexpected package separator found in path: ", path); 81 } 82 83 rest = parts[2]; 84 return parts[0]; 85 } 86 87 88 /** 89 * Match path of a directory or a file relative to a parent directory with 90 * a glob pattern. 91 * 92 * Params: path = Path of the file/directory. 93 * parentPath = Path of the parent directory. 94 * glob = Glob pattern to match with. If null, a match is assumed. 95 * 96 * Returns: True on match or if glob is null; false otherwise. 97 */ 98 bool subPathMatch(string path, string parentPath, string glob) @safe pure 99 { 100 if(glob is null) { return true; } 101 auto relative = path; 102 relative.skipOver(parentPath); 103 relative.skipOver("/"); 104 return globMatch(relative, glob); 105 }