From 20f50ad90fd18f1dd7dbb95c861a00dc3e6f782a Mon Sep 17 00:00:00 2001 From: David Rajchenbach-Teller Date: Wed, 18 Jul 2012 21:09:14 -0400 Subject: [PATCH] Bug 769310 - Windows paths. r=taras --- toolkit/components/osfile/Makefile.in | 1 + toolkit/components/osfile/osfile_win_back.jsm | 248 ----------------- .../components/osfile/osfile_win_front.jsm | 1 + toolkit/components/osfile/ospath_win_back.jsm | 259 ++++++++++++++++++ 4 files changed, 261 insertions(+), 248 deletions(-) create mode 100644 toolkit/components/osfile/ospath_win_back.jsm diff --git a/toolkit/components/osfile/Makefile.in b/toolkit/components/osfile/Makefile.in index 2d82c0cec67..b9484fce767 100644 --- a/toolkit/components/osfile/Makefile.in +++ b/toolkit/components/osfile/Makefile.in @@ -26,5 +26,6 @@ libs:: $(NSINSTALL) $(srcdir)/osfile_shared.jsm $(FINAL_TARGET)/modules/osfile $(NSINSTALL) $(srcdir)/osfile_unix_back.jsm $(FINAL_TARGET)/modules/osfile $(NSINSTALL) $(srcdir)/osfile_unix_front.jsm $(FINAL_TARGET)/modules/osfile + $(NSINSTALL) $(srcdir)/ospath_win_back.jsm $(FINAL_TARGET)/modules/osfile $(NSINSTALL) $(srcdir)/osfile_win_back.jsm $(FINAL_TARGET)/modules/osfile $(NSINSTALL) $(srcdir)/osfile_win_front.jsm $(FINAL_TARGET)/modules/osfile diff --git a/toolkit/components/osfile/osfile_win_back.jsm b/toolkit/components/osfile/osfile_win_back.jsm index cab60098403..765d98cf7b9 100644 --- a/toolkit/components/osfile/osfile_win_back.jsm +++ b/toolkit/components/osfile/osfile_win_back.jsm @@ -308,254 +308,6 @@ /*overlapped*/Types.void_t.inout_ptr // FIXME: Implement? ); - /** - * Utility function: check that a path is not a UNC path, - * as the current implementation of |Path| does not support - * UNC grammars. - * - * We consider that any path starting with "\\\\" is a UNC path. - */ - let ensureNotUNC = function ensureNotUNC(path) { - if (!path) { - throw new TypeError("Expecting a non-null path"); - } - if (path.length >= 2 && path[0] == "\\" && path[1] == "\\") { - throw new Error("Module Path cannot handle UNC-formatted paths yet: " + path); - } - }; - - /** - * Utility function: Remove any leading/trailing backslashes - * from a string. - */ - let trimBackslashes = function trimBackslashes(string) { - return string.replace(/^\\+|\\+$/g,''); - }; - - /** - * Handling native paths. - * - * This module contains a number of functions destined to simplify - * working with native paths through a cross-platform API. Functions - * of this module will only work with the following assumptions: - * - * - paths are valid; - * - paths are defined with one of the grammars that this module can - * parse (see later); - * - all path concatenations go through function |join|. - * - * Limitations of this implementation. - * - * Windows supports 6 distinct grammars for paths. For the moment, this - * implementation supports the following subset: - * - * - drivename:backslash-separated components - * - backslash-separated components - * - * Additionally, |normalize| can convert a path containing slash- - * separated components to a path containing backslash-separated - * components. - */ - exports.OS.Win.Path = { - /** - * Return the final part of the path. - * The final part of the path is everything after the last "\\". - */ - basename: function basename(path) { - ensureNotUNC(path); - return path.slice(Math.max(path.lastIndexOf("\\"), - path.lastIndexOf(":")) + 1); - }, - - /** - * Return the directory part of the path. The directory part - * of the path is everything before the last "\\", including - * the drive/server name. - * - * If the path contains no directory, return the drive letter, - * or "." if the path contains no drive letter or if option - * |winNoDrive| is set. - * - * @param {string} path The path. - * @param {*=} options Platform-specific options controlling the behavior - * of this function. This implementation supports the following options: - * - |winNoDrive| If |true|, also remove the letter from the path name. - */ - dirname: function dirname(path, options) { - ensureNotUNC(path); - let noDrive = (options && options.winNoDrive); - - // Find the last occurrence of "\\" - let index = path.lastIndexOf("\\"); - if (index == -1) { - // If there is no directory component... - if (!noDrive) { - // Return the drive path if possible, falling back to "." - return this.winGetDrive(path) || "."; - } else { - // Or just "." - return "."; - } - } - - // Ignore any occurrence of "\\: immediately before that one - while (index >= 0 && path[index] == "\\") { - --index; - } - - // Compute what is left, removing the drive name if necessary - let start; - if (noDrive) { - start = (this.winGetDrive(path) || "").length; - } else { - start = 0; - } - return path.slice(start, index + 1); - }, - - /** - * Join path components. - * This is the recommended manner of getting the path of a file/subdirectory - * in a directory. - * - * Example: Obtaining $TMP/foo/bar in an OS-independent manner - * var tmpDir = OS.Path.to("TmpD"); - * var path = OS.Path.join(tmpDir, "foo", "bar"); - * - * Under Windows, this will return "$TMP\foo\bar". - */ - join: function join(path /*...*/) { - let paths = []; - let root; - let absolute = false; - for each(let subpath in arguments) { - let drive = this.winGetDrive(subpath); - let abs = this.winIsAbsolute(subpath); - if (drive) { - root = drive; - paths = [trimBackslashes(subpath.slice(drive.length))]; - absolute = abs; - } else if (abs) { - paths = [trimBackslashes(subpath)]; - absolute = true; - } else { - paths.push(trimBackslashes(subpath)); - } - } - let result = ""; - if (root) { - result += root; - } - if (absolute) { - result += "\\"; - } - result += paths.join("\\"); - return result; - }, - - /** - * Return the drive letter of a path, or |null| if the - * path does not contain a drive letter. - */ - winGetDrive: function winGetDrive(path) { - ensureNotUNC(path); - let index = path.indexOf(":"); - if (index <= 0) return null; - return path.slice(0, index + 1); - }, - - /** - * Return |true| if the path is absolute, |false| otherwise. - * - * We consider that a path is absolute if it starts with "\\" - * or "driveletter:\\". - */ - winIsAbsolute: function winIsAbsolute(path) { - ensureNotUNC(path); - return this._winIsAbsolute(path); - }, - /** - * As |winIsAbsolute|, but does not check for UNC. - * Useful mostly as an internal utility, for normalization. - */ - _winIsAbsolute: function _winIsAbsolute(path) { - let index = path.indexOf(":"); - return path.length > index + 1 && path[index + 1] == "\\"; - }, - - /** - * Normalize a path by removing any unneeded ".", "..", "\\". - * Also convert any "/" to a "\\". - */ - normalize: function normalize(path) { - let stack = []; - - // Remove the drive (we will put it back at the end) - let root = this.winGetDrive(path); - if (root) { - path = path.slice(root.length); - } - - // Remember whether we need to restore a leading "\\". - let absolute = this._winIsAbsolute(path); - - // Normalize "/" to "\\" - path = path.replace("/", "\\"); - - // And now, fill |stack| from the components, - // popping whenever there is a ".." - path.split("\\").forEach(function loop(v) { - switch (v) { - case "": case ".": // Ignore - break; - case "..": - if (stack.length == 0) { - if (absolute) { - throw new Error("Path is ill-formed: attempting to go past root"); - } else { - stack.push(".."); - } - } else { - stack.pop(); - } - break; - default: - stack.push(v); - } - }); - - // Put everything back together - let result = stack.join("\\"); - if (absolute) { - result = "\\" + result; - } - if (root) { - result = root + result; - } - return result; - }, - - /** - * Return the components of a path. - * You should generally apply this function to a normalized path. - * - * @return {{ - * {bool} absolute |true| if the path is absolute, |false| otherwise - * {array} components the string components of the path - * {string?} winDrive the drive or server for this path - * }} - * - * Other implementations may add additional OS-specific informations. - */ - split: function split(path) { - return { - absolute: this.winIsAbsolute(path), - winDrive: this.winGetDrive(path), - components: path.split("\\") - }; - } - }; - // Export useful stuff for extensibility exports.OS.Win.libc = libc; diff --git a/toolkit/components/osfile/osfile_win_front.jsm b/toolkit/components/osfile/osfile_win_front.jsm index 24bff84fd22..27eaae151af 100644 --- a/toolkit/components/osfile/osfile_win_front.jsm +++ b/toolkit/components/osfile/osfile_win_front.jsm @@ -18,6 +18,7 @@ importScripts("resource://gre/modules/osfile/osfile_shared.jsm"); importScripts("resource://gre/modules/osfile/osfile_win_back.jsm"); + importScripts("resource://gre/modules/osfile/ospath_win_back.jsm"); (function(exports) { "use strict"; diff --git a/toolkit/components/osfile/ospath_win_back.jsm b/toolkit/components/osfile/ospath_win_back.jsm new file mode 100644 index 00000000000..7687e2d3a17 --- /dev/null +++ b/toolkit/components/osfile/ospath_win_back.jsm @@ -0,0 +1,259 @@ +/** + * Handling native paths. + * + * This module contains a number of functions destined to simplify + * working with native paths through a cross-platform API. Functions + * of this module will only work with the following assumptions: + * + * - paths are valid; + * - paths are defined with one of the grammars that this module can + * parse (see later); + * - all path concatenations go through function |join|. + * + * Limitations of this implementation. + * + * Windows supports 6 distinct grammars for paths. For the moment, this + * implementation supports the following subset: + * + * - drivename:backslash-separated components + * - backslash-separated components + * + * Additionally, |normalize| can convert a path containing slash- + * separated components to a path containing backslash-separated + * components. + */ +(function(exports) { + "use strict"; + if (!exports.OS) { + exports.OS = {}; + } + if (!exports.OS.Win) { + exports.OS.Win = {}; + } + if (exports.OS.Win.Path) { + return; // Avoid double-initialization + } + exports.OS.Win.Path = { + /** + * Return the final part of the path. + * The final part of the path is everything after the last "\\". + */ + basename: function basename(path) { + ensureNotUNC(path); + return path.slice(Math.max(path.lastIndexOf("\\"), + path.lastIndexOf(":")) + 1); + }, + + /** + * Return the directory part of the path. The directory part + * of the path is everything before the last "\\", including + * the drive/server name. + * + * If the path contains no directory, return the drive letter, + * or "." if the path contains no drive letter or if option + * |winNoDrive| is set. + * + * @param {string} path The path. + * @param {*=} options Platform-specific options controlling the behavior + * of this function. This implementation supports the following options: + * - |winNoDrive| If |true|, also remove the letter from the path name. + */ + dirname: function dirname(path, options) { + ensureNotUNC(path); + let noDrive = (options && options.winNoDrive); + + // Find the last occurrence of "\\" + let index = path.lastIndexOf("\\"); + if (index == -1) { + // If there is no directory component... + if (!noDrive) { + // Return the drive path if possible, falling back to "." + return this.winGetDrive(path) || "."; + } else { + // Or just "." + return "."; + } + } + + // Ignore any occurrence of "\\: immediately before that one + while (index >= 0 && path[index] == "\\") { + --index; + } + + // Compute what is left, removing the drive name if necessary + let start; + if (noDrive) { + start = (this.winGetDrive(path) || "").length; + } else { + start = 0; + } + return path.slice(start, index + 1); + }, + + /** + * Join path components. + * This is the recommended manner of getting the path of a file/subdirectory + * in a directory. + * + * Example: Obtaining $TMP/foo/bar in an OS-independent manner + * var tmpDir = OS.Path.to("TmpD"); + * var path = OS.Path.join(tmpDir, "foo", "bar"); + * + * Under Windows, this will return "$TMP\foo\bar". + */ + join: function join(path /*...*/) { + let paths = []; + let root; + let absolute = false; + for each(let subpath in arguments) { + let drive = this.winGetDrive(subpath); + let abs = this.winIsAbsolute(subpath); + if (drive) { + root = drive; + paths = [trimBackslashes(subpath.slice(drive.length))]; + absolute = abs; + } else if (abs) { + paths = [trimBackslashes(subpath)]; + absolute = true; + } else { + paths.push(trimBackslashes(subpath)); + } + } + let result = ""; + if (root) { + result += root; + } + if (absolute) { + result += "\\"; + } + result += paths.join("\\"); + return result; + }, + + /** + * Return the drive letter of a path, or |null| if the + * path does not contain a drive letter. + */ + winGetDrive: function winGetDrive(path) { + ensureNotUNC(path); + let index = path.indexOf(":"); + if (index <= 0) return null; + return path.slice(0, index + 1); + }, + + /** + * Return |true| if the path is absolute, |false| otherwise. + * + * We consider that a path is absolute if it starts with "\\" + * or "driveletter:\\". + */ + winIsAbsolute: function winIsAbsolute(path) { + ensureNotUNC(path); + return this._winIsAbsolute(path); + }, + /** + * As |winIsAbsolute|, but does not check for UNC. + * Useful mostly as an internal utility, for normalization. + */ + _winIsAbsolute: function _winIsAbsolute(path) { + let index = path.indexOf(":"); + return path.length > index + 1 && path[index + 1] == "\\"; + }, + + /** + * Normalize a path by removing any unneeded ".", "..", "\\". + * Also convert any "/" to a "\\". + */ + normalize: function normalize(path) { + let stack = []; + + // Remove the drive (we will put it back at the end) + let root = this.winGetDrive(path); + if (root) { + path = path.slice(root.length); + } + + // Remember whether we need to restore a leading "\\". + let absolute = this._winIsAbsolute(path); + + // Normalize "/" to "\\" + path = path.replace("/", "\\"); + + // And now, fill |stack| from the components, + // popping whenever there is a ".." + path.split("\\").forEach(function loop(v) { + switch (v) { + case "": case ".": // Ignore + break; + case "..": + if (stack.length == 0) { + if (absolute) { + throw new Error("Path is ill-formed: attempting to go past root"); + } else { + stack.push(".."); + } + } else { + stack.pop(); + } + break; + default: + stack.push(v); + } + }); + + // Put everything back together + let result = stack.join("\\"); + if (absolute) { + result = "\\" + result; + } + if (root) { + result = root + result; + } + return result; + }, + + /** + * Return the components of a path. + * You should generally apply this function to a normalized path. + * + * @return {{ + * {bool} absolute |true| if the path is absolute, |false| otherwise + * {array} components the string components of the path + * {string?} winDrive the drive or server for this path + * }} + * + * Other implementations may add additional OS-specific informations. + */ + split: function split(path) { + return { + absolute: this.winIsAbsolute(path), + winDrive: this.winGetDrive(path), + components: path.split("\\") + }; + } + }; + + /** + * Utility function: check that a path is not a UNC path, + * as the current implementation of |Path| does not support + * UNC grammars. + * + * We consider that any path starting with "\\\\" is a UNC path. + */ + let ensureNotUNC = function ensureNotUNC(path) { + if (!path) { + throw new TypeError("Expecting a non-null path"); + } + if (path.length >= 2 && path[0] == "\\" && path[1] == "\\") { + throw new Error("Module Path cannot handle UNC-formatted paths yet: " + path); + } + }; + + /** + * Utility function: Remove any leading/trailing backslashes + * from a string. + */ + let trimBackslashes = function trimBackslashes(string) { + return string.replace(/^\\+|\\+$/g,''); + }; +}(this));