toolkit/components/osfile/modules/ospath_unix.jsm

changeset 0
6474c204b198
     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 +}

mercurial