1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/toolkit/components/osfile/modules/ospath_unix.jsm Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,194 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this file, 1.6 + * You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +/** 1.9 + * Handling native paths. 1.10 + * 1.11 + * This module contains a number of functions destined to simplify 1.12 + * working with native paths through a cross-platform API. Functions 1.13 + * of this module will only work with the following assumptions: 1.14 + * 1.15 + * - paths are valid; 1.16 + * - paths are defined with one of the grammars that this module can 1.17 + * parse (see later); 1.18 + * - all path concatenations go through function |join|. 1.19 + */ 1.20 + 1.21 +"use strict"; 1.22 + 1.23 +// Boilerplate used to be able to import this module both from the main 1.24 +// thread and from worker threads. 1.25 +if (typeof Components != "undefined") { 1.26 + Components.utils.importGlobalProperties(["URL"]); 1.27 + // Global definition of |exports|, to keep everybody happy. 1.28 + // In non-main thread, |exports| is provided by the module 1.29 + // loader. 1.30 + this.exports = {}; 1.31 +} else if (typeof "module" == "undefined" || typeof "exports" == "undefined") { 1.32 + throw new Error("Please load this module using require()"); 1.33 +} 1.34 + 1.35 +let EXPORTED_SYMBOLS = [ 1.36 + "basename", 1.37 + "dirname", 1.38 + "join", 1.39 + "normalize", 1.40 + "split", 1.41 + "toFileURI", 1.42 + "fromFileURI", 1.43 +]; 1.44 + 1.45 +/** 1.46 + * Return the final part of the path. 1.47 + * The final part of the path is everything after the last "/". 1.48 + */ 1.49 +let basename = function(path) { 1.50 + return path.slice(path.lastIndexOf("/") + 1); 1.51 +}; 1.52 +exports.basename = basename; 1.53 + 1.54 +/** 1.55 + * Return the directory part of the path. 1.56 + * The directory part of the path is everything before the last 1.57 + * "/". If the last few characters of this part are also "/", 1.58 + * they are ignored. 1.59 + * 1.60 + * If the path contains no directory, return ".". 1.61 + */ 1.62 +let dirname = function(path) { 1.63 + let index = path.lastIndexOf("/"); 1.64 + if (index == -1) { 1.65 + return "."; 1.66 + } 1.67 + while (index >= 0 && path[index] == "/") { 1.68 + --index; 1.69 + } 1.70 + return path.slice(0, index + 1); 1.71 +}; 1.72 +exports.dirname = dirname; 1.73 + 1.74 +/** 1.75 + * Join path components. 1.76 + * This is the recommended manner of getting the path of a file/subdirectory 1.77 + * in a directory. 1.78 + * 1.79 + * Example: Obtaining $TMP/foo/bar in an OS-independent manner 1.80 + * var tmpDir = OS.Constants.Path.tmpDir; 1.81 + * var path = OS.Path.join(tmpDir, "foo", "bar"); 1.82 + * 1.83 + * Under Unix, this will return "/tmp/foo/bar". 1.84 + */ 1.85 +let join = function(...path) { 1.86 + // If there is a path that starts with a "/", eliminate everything before 1.87 + let paths = []; 1.88 + for (let subpath of path) { 1.89 + if (subpath == null) { 1.90 + throw new TypeError("invalid path component"); 1.91 + } 1.92 + if (subpath.length != 0 && subpath[0] == "/") { 1.93 + paths = [subpath]; 1.94 + } else { 1.95 + paths.push(subpath); 1.96 + } 1.97 + } 1.98 + return paths.join("/"); 1.99 +}; 1.100 +exports.join = join; 1.101 + 1.102 +/** 1.103 + * Normalize a path by removing any unneeded ".", "..", "//". 1.104 + */ 1.105 +let normalize = function(path) { 1.106 + let stack = []; 1.107 + let absolute; 1.108 + if (path.length >= 0 && path[0] == "/") { 1.109 + absolute = true; 1.110 + } else { 1.111 + absolute = false; 1.112 + } 1.113 + path.split("/").forEach(function(v) { 1.114 + switch (v) { 1.115 + case "": case ".":// fallthrough 1.116 + break; 1.117 + case "..": 1.118 + if (stack.length == 0) { 1.119 + if (absolute) { 1.120 + throw new Error("Path is ill-formed: attempting to go past root"); 1.121 + } else { 1.122 + stack.push(".."); 1.123 + } 1.124 + } else { 1.125 + if (stack[stack.length - 1] == "..") { 1.126 + stack.push(".."); 1.127 + } else { 1.128 + stack.pop(); 1.129 + } 1.130 + } 1.131 + break; 1.132 + default: 1.133 + stack.push(v); 1.134 + } 1.135 + }); 1.136 + let string = stack.join("/"); 1.137 + return absolute ? "/" + string : string; 1.138 +}; 1.139 +exports.normalize = normalize; 1.140 + 1.141 +/** 1.142 + * Return the components of a path. 1.143 + * You should generally apply this function to a normalized path. 1.144 + * 1.145 + * @return {{ 1.146 + * {bool} absolute |true| if the path is absolute, |false| otherwise 1.147 + * {array} components the string components of the path 1.148 + * }} 1.149 + * 1.150 + * Other implementations may add additional OS-specific informations. 1.151 + */ 1.152 +let split = function(path) { 1.153 + return { 1.154 + absolute: path.length && path[0] == "/", 1.155 + components: path.split("/") 1.156 + }; 1.157 +}; 1.158 +exports.split = split; 1.159 + 1.160 +/** 1.161 + * Returns the file:// URI file path of the given local file path. 1.162 + */ 1.163 +// The case of %3b is designed to match Services.io, but fundamentally doesn't matter. 1.164 +let toFileURIExtraEncodings = {';': '%3b', '?': '%3F', "'": '%27', '#': '%23'}; 1.165 +let toFileURI = function toFileURI(path) { 1.166 + let uri = encodeURI(this.normalize(path)); 1.167 + 1.168 + // add a prefix, and encodeURI doesn't escape a few characters that we do 1.169 + // want to escape, so fix that up 1.170 + let prefix = "file://"; 1.171 + uri = prefix + uri.replace(/[;?'#]/g, match => toFileURIExtraEncodings[match]); 1.172 + 1.173 + return uri; 1.174 +}; 1.175 +exports.toFileURI = toFileURI; 1.176 + 1.177 +/** 1.178 + * Returns the local file path from a given file URI. 1.179 + */ 1.180 +let fromFileURI = function fromFileURI(uri) { 1.181 + let url = new URL(uri); 1.182 + if (url.protocol != 'file:') { 1.183 + throw new Error("fromFileURI expects a file URI"); 1.184 + } 1.185 + let path = this.normalize(decodeURIComponent(url.pathname)); 1.186 + return path; 1.187 +}; 1.188 +exports.fromFileURI = fromFileURI; 1.189 + 1.190 + 1.191 +//////////// Boilerplate 1.192 +if (typeof Components != "undefined") { 1.193 + this.EXPORTED_SYMBOLS = EXPORTED_SYMBOLS; 1.194 + for (let symbol of EXPORTED_SYMBOLS) { 1.195 + this[symbol] = exports[symbol]; 1.196 + } 1.197 +}