2 * (C) Copyright 2007,2010 John J. Foerch
3 * (C) Copyright 2007-2008 Jeremy Maitin-Shepard.
5 * Portions of this file were derived from Mozilla,
6 * (C) Copyright 1998-2007 Mozilla Foundation.
8 * Use, modification, and distribution are subject to the terms specified in the
13 * maybe_get_filename_extension
15 * file_name_s: string filename, may be null.
17 * returns null or extension part of file_name_s.
19 function maybe_get_filename_extension (file_name_s) {
20 var url = Cc["@mozilla.org/network/standard-url;1"]
21 .createInstance(Ci.nsIURL);
22 url.filePath = file_name_s;
23 if (url.fileExtension == '')
25 return url.fileExtension;
29 function maybe_get_url_extension (url_o) {
31 var url = url_o.QueryInterface(Ci.nsIURL);
32 if (url.fileExtension == '')
34 return url.fileExtension;
41 * maybe_get_preferred_filename_extension
43 * file_name_s: string filename, may be null.
45 * content_type: string content type, may be null.
47 * returns null, the default extension for the given
48 * content type, or the extension part of file_name_s.
50 function maybe_get_preferred_filename_extension (file_name_s, content_type) {
51 var ext = maybe_get_filename_extension (file_name_s);
56 // throws if content_type is an empty string
57 mimeInfo = Cc["@mozilla.org/mime;1"]
58 .getService(Ci.nsIMIMEService)
59 .getFromTypeAndExtension(content_type, ext);
60 primary = mimeInfo.primaryExtension;
63 if (ext && mimeInfo && mimeInfo.extensionExists(ext))
72 function maybe_get_preferred_url_extension (url_o, content_type) {
73 var ext = maybe_get_url_extension(url_o);
78 mimeInfo = Cc["@mozilla.org/mime;1"]
79 .getService(Ci.nsIMIMEService)
80 .getFromTypeAndExtension(content_type, null);
81 primary = mimeInfo.primaryExtension;
84 if (ext && mimeInfo && mimeInfo.extensionExists(ext))
92 function get_default_extension (file_name_s, url_o, content_type) {
93 if (content_type == "text/plain" ||
94 content_type == "application/octet-stream" ||
95 url_o.scheme == "ftp")
99 return (maybe_get_preferred_filename_extension(file_name_s, content_type) ||
100 maybe_get_preferred_url_extension(url_o, content_type));
103 function get_charset_for_save (doc) {
105 return doc.characterSet;
109 function maybe_filename_from_content_disposition (spec) {
110 var document = load_spec_document(spec);
111 var content_disposition = (document && get_document_content_disposition(document));
112 var charset = get_charset_for_save(document);
113 if (content_disposition) {
114 const mhp = Cc["@mozilla.org/network/mime-hdrparam;1"]
115 .getService(Ci.nsIMIMEHeaderParam);
116 var dummy = { value: null }; // Need an out param...
120 filename = mhp.getParameter(content_disposition, "filename", charset, true, dummy);
123 filename = mhp.getParameter(content_disposition, "name", charset, true, dummy);
134 function maybe_filename_from_uri (spec) {
135 var uri = load_spec_uri(spec);
137 var url = uri.QueryInterface(Ci.nsIURL);
138 if (url.fileName != "") {
139 // 2) Use the actual file name, if present
140 var text_to_sub_uri = Cc["@mozilla.org/intl/texttosuburi;1"].
141 getService(Ci.nsITextToSubURI);
142 return text_to_sub_uri.unEscapeURIForUI(url.originCharset ||
143 "UTF-8", url.fileName);
146 // This is something like a data: and so forth URI... no filename here.
152 * maybe_filename_from_title returns a filename from the load-spec's title
153 * property if and only if the load-spec has neither a document nor an
154 * element property. In those cases, defer to generating the filename
157 function maybe_filename_from_title (spec) {
158 if (load_spec_document(spec) || load_spec_element(spec))
160 var title = load_spec_title(spec);
162 title = trim_whitespace(title);
169 function maybe_filename_from_url_last_directory (spec) {
170 var uri = load_spec_uri(spec);
172 var path = uri.path.match(/\/([^\/]+)\/$/);
173 if (path && path.length > 1)
174 return path[1] + ".";
181 function maybe_filename_from_url_host (spec) {
182 var uri = load_spec_uri(spec);
183 if (uri && 'host' in uri) {
185 return uri.host + ".";
191 function maybe_filename_from_localization_default () {
193 return getStringBundle().GetStringFromName("DefaultSaveFileName");
201 * Sanitize filename for various platforms.
204 function generate_filename_safely_default (filename) {
205 return filename.replace(/[\/]+/g, '_');
208 function generate_filename_safely_darwin (filename) {
209 return filename.replace(/[\:\/]+/g, '_');
212 function generate_filename_safely_winnt (filename) {
213 filename = filename.replace(/[\"]+/g, "'");
214 filename = filename.replace(/[\*\:\?]+/g, ' ');
215 filename = filename.replace(/[\<]+/g, '(');
216 filename = filename.replace(/[\>]+/g, ')');
217 filename = filename.replace(/[\\\/\|]+/g, '_');
222 define_variable("generate_filename_safely_fn",
223 ({ Darwin: generate_filename_safely_darwin,
224 WINNT: generate_filename_safely_winnt }[get_os()]
225 || generate_filename_safely_default),
226 "Function to sanitize the filenames generated by suggest_file_name "+
227 "for the current platform.");
231 * spec may be a string (URI), a load spec, or an nsIDOMDocument
233 * extension may be null, in which case an extension is suggested as well
235 function suggest_file_name (spec, extension) {
236 if (typeof spec == "string" || spec instanceof Ci.nsIDOMDocument)
237 spec = load_spec(spec);
239 var file_name = load_spec_filename(spec);
240 var uri = load_spec_uri(spec);
241 var content_type = load_spec_mime_type(spec);
244 file_name = generate_filename_safely_fn(
245 maybe_filename_from_content_disposition(spec) ||
246 maybe_filename_from_title(spec) ||
247 maybe_filename_from_uri(spec) ||
248 maybe_filename_from_url_last_directory(spec) ||
249 maybe_filename_from_url_host(spec) ||
250 maybe_filename_from_localization_default() ||
253 var base_name = file_name.replace(/\.[^.]*$/, "");
255 var file_ext = extension || load_spec_filename_extension(spec);
258 file_ext = get_default_extension(file_name, uri, content_type);
259 if (file_ext == "") {
260 let x = file_name.lastIndexOf(".");
264 file_ext = file_name.substring(x+1);
266 if (!file_ext && (/^http(s?)/i).test(uri.scheme) && !content_type ||
267 content_type == "application/octet-stream")
273 if (file_ext != null && file_ext.length > 0)
274 return base_name + "." + file_ext;
279 function suggest_save_path_from_file_name (file_name, buffer) {
280 var cwd = with_current_buffer(buffer, function (I) I.local.cwd);
281 var file = cwd.clone();
282 file.append(file_name);
286 provide("suggest-file-name");