toolkit/mozapps/downloads/DownloadPaths.jsm

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/mozapps/downloads/DownloadPaths.jsm	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,89 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +this.EXPORTED_SYMBOLS = [
    1.11 +  "DownloadPaths",
    1.12 +];
    1.13 +
    1.14 +/**
    1.15 + * This module provides the DownloadPaths object which contains methods for
    1.16 + * giving names and paths to files being downloaded.
    1.17 + *
    1.18 + * List of methods:
    1.19 + *
    1.20 + * nsILocalFile
    1.21 + * createNiceUniqueFile(nsILocalFile aLocalFile)
    1.22 + *
    1.23 + * [string base, string ext]
    1.24 + * splitBaseNameAndExtension(string aLeafName)
    1.25 + */
    1.26 +
    1.27 +const Cc = Components.classes;
    1.28 +const Ci = Components.interfaces;
    1.29 +const Cu = Components.utils;
    1.30 +const Cr = Components.results;
    1.31 +
    1.32 +this.DownloadPaths = {
    1.33 +  /**
    1.34 +   * Creates a uniquely-named file starting from the name of the provided file.
    1.35 +   * If a file with the provided name already exists, the function attempts to
    1.36 +   * create nice alternatives, like "base(1).ext" (instead of "base-1.ext").
    1.37 +   *
    1.38 +   * If a unique name cannot be found, the function throws the XPCOM exception
    1.39 +   * NS_ERROR_FILE_TOO_BIG. Other exceptions, like NS_ERROR_FILE_ACCESS_DENIED,
    1.40 +   * can also be expected.
    1.41 +   *
    1.42 +   * @param aTemplateFile
    1.43 +   *        nsILocalFile whose leaf name is going to be used as a template. The
    1.44 +   *        provided object is not modified.
    1.45 +   * @returns A new instance of an nsILocalFile object pointing to the newly
    1.46 +   *          created empty file. On platforms that support permission bits, the
    1.47 +   *          file is created with permissions 644.
    1.48 +   */
    1.49 +  createNiceUniqueFile: function DP_createNiceUniqueFile(aTemplateFile) {
    1.50 +    // Work on a clone of the provided template file object.
    1.51 +    var curFile = aTemplateFile.clone().QueryInterface(Ci.nsILocalFile);
    1.52 +    var [base, ext] = DownloadPaths.splitBaseNameAndExtension(curFile.leafName);
    1.53 +    // Try other file names, for example "base(1).txt" or "base(1).tar.gz",
    1.54 +    // only if the file name initially set already exists.
    1.55 +    for (let i = 1; i < 10000 && curFile.exists(); i++) {
    1.56 +      curFile.leafName = base + "(" + i + ")" + ext;
    1.57 +    }
    1.58 +    // At this point we hand off control to createUnique, which will create the
    1.59 +    // file with the name we chose, if it is valid. If not, createUnique will
    1.60 +    // attempt to modify it again, for example it will shorten very long names
    1.61 +    // that can't be created on some platforms, and for which a normal call to
    1.62 +    // nsIFile.create would result in NS_ERROR_FILE_NOT_FOUND. This can result
    1.63 +    // very rarely in strange names like "base(9999).tar-1.gz" or "ba-1.gz".
    1.64 +    curFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0644);
    1.65 +    return curFile;
    1.66 +  },
    1.67 +
    1.68 +  /**
    1.69 +   * Separates the base name from the extension in a file name, recognizing some
    1.70 +   *  double extensions like ".tar.gz".
    1.71 +   *
    1.72 +   * @param aLeafName
    1.73 +   *        The full leaf name to be parsed. Be careful when processing names
    1.74 +   *        containing leading or trailing dots or spaces.
    1.75 +   * @returns [base, ext]
    1.76 +   *          The base name of the file, which can be empty, and its extension,
    1.77 +   *          which always includes the leading dot unless it's an empty string.
    1.78 +   *          Concatenating the two items always results in the original name.
    1.79 +   */
    1.80 +  splitBaseNameAndExtension: function DP_splitBaseNameAndExtension(aLeafName) {
    1.81 +    // The following regular expression is built from these key parts:
    1.82 +    //  .*?                      Matches the base name non-greedily.
    1.83 +    //  \.[A-Z0-9]{1,3}          Up to three letters or numbers preceding a
    1.84 +    //                           double extension.
    1.85 +    //  \.(?:gz|bz2|Z)           The second part of common double extensions.
    1.86 +    //  \.[^.]*                  Matches any extension or a single trailing dot.
    1.87 +    var [, base, ext] = /(.*?)(\.[A-Z0-9]{1,3}\.(?:gz|bz2|Z)|\.[^.]*)?$/i
    1.88 +                        .exec(aLeafName);
    1.89 +    // Return an empty string instead of undefined if no extension is found.
    1.90 +    return [base, ext || ""];
    1.91 +  }
    1.92 +};

mercurial