2 * (C) Copyright 2007 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
12 /* maybe_get_filename_extension
14 * file_name_s: string filename, may be null.
16 * returns null or extension part of file_name_s.
18 function maybe_get_filename_extension (file_name_s) {
19 var url = Components.classes["@mozilla.org/network/standard-url;1"]
20 .createInstance(Components.interfaces.nsIURL);
21 url.filePath = file_name_s;
22 if (url.fileExtension == '')
24 return url.fileExtension;
28 function maybe_get_url_extension (url_o) {
30 var url = url_o.QueryInterface(Components.interfaces.nsIURL);
31 if (url.fileExtension == '')
33 return url.fileExtension;
39 /* maybe_get_preferred_filename_extension
41 * file_name_s: string filename, may be null.
43 * content_type: string content type, may be null.
45 * returns null, the default extension for the given
46 * content type, or the extension part of file_name_s.
48 function maybe_get_preferred_filename_extension (file_name_s, content_type) {
49 var ext = maybe_get_filename_extension (file_name_s);
54 // throws if content_type is an empty string
55 mimeInfo = Components.classes["@mozilla.org/mime;1"]
56 .getService(Components.interfaces.nsIMIMEService)
57 .getFromTypeAndExtension(content_type, ext);
58 primary = mimeInfo.primaryExtension;
61 if (ext && mimeInfo && mimeInfo.extensionExists(ext))
70 function maybe_get_preferred_url_extension (url_o, content_type) {
71 var ext = maybe_get_url_extension(url_o);
76 mimeInfo = Components.classes["@mozilla.org/mime;1"]
77 .getService(Components.interfaces.nsIMIMEService)
78 .getFromTypeAndExtension(content_type, null);
79 primary = mimeInfo.primaryExtension;
82 if (ext && mimeInfo && mimeInfo.extensionExists(ext))
90 function get_default_extension (file_name_s, url_o, content_type) {
91 if (content_type == "text/plain" ||
92 content_type == "application/octet-stream" ||
93 url_o.scheme == "ftp")
97 return (maybe_get_preferred_filename_extension(file_name_s, content_type) ||
98 maybe_get_preferred_url_extension(url_o, content_type));
101 function get_charset_for_save (doc) {
103 return doc.characterSet;
108 function maybe_filename_from_content_disposition (content_disposition, charset) {
109 if (content_disposition) {
110 const mhp = Components.classes["@mozilla.org/network/mime-hdrparam;1"]
111 .getService(Components.interfaces.nsIMIMEHeaderParam);
112 var dummy = { value: null }; // Need an out param...
116 filename = mhp.getParameter(content_disposition, "filename", charset, true, dummy);
119 filename = mhp.getParameter(content_disposition, "name", charset, true, dummy);
130 function maybe_filename_from_uri (uri) {
132 var url = uri.QueryInterface(Components.interfaces.nsIURL);
133 if (url.fileName != "") {
134 // 2) Use the actual file name, if present
135 var text_to_sub_uri = Cc["@mozilla.org/intl/texttosuburi;1"].
136 getService(Ci.nsITextToSubURI);
137 return text_to_sub_uri.unEscapeURIForUI(url.originCharset ||
138 "UTF-8", url.fileName);
141 // This is something like a data: and so forth URI... no filename here.
146 function maybe_filename_from_title (title) {
148 title = title.replace(/^\s+|\s+$/g, "");
149 if (title && title.length > 0) {
150 // 3) Use the document title
157 function maybe_filename_from_url_last_directory (uri) {
158 // 5) If this is a directory, use the last directory name
160 var path = uri.path.match(/\/([^\/]+)\/$/);
161 if (path && path.length > 1)
169 function maybe_filename_from_url_host (uri) {
170 if (uri && 'host' in uri)
175 function maybe_filename_from_localization_default () {
177 return getStringBundle().GetStringFromName("DefaultSaveFileName");
183 function generate_filename_safely_default (filename) {
184 return filename.replace(/[\/]+/g, '_');
187 function generate_filename_safely_darwin (filename) {
188 return filename.replace(/[\:\/]+/g, '_');
191 function generate_filename_safely_winnt (filename) {
192 filename = filename.replace(/[\"]+/g, "'");
193 filename = filename.replace(/[\*\:\?]+/g, ' ');
194 filename = filename.replace(/[\<]+/g, '(');
195 filename = filename.replace(/[\>]+/g, ')');
196 filename = filename.replace(/[\\\/\|]+/g, '_');
201 var generate_filename_safely_fn = null;
205 generate_filename_safely_fn = generate_filename_safely_darwin;
208 generate_filename_safely_fn = generate_filename_safely_winnt;
211 generate_filename_safely_fn = generate_filename_safely_default;
216 * spec may be a string (URI), a load spec, or an nsIDOMDocument
218 * extension may be null, in which case an extension is suggested as well
220 function suggest_file_name (spec, extension) {
225 if (typeof(spec) == "string" || spec instanceof Ci.nsIDOMDocument)
226 spec = load_spec(spec);
228 var file_name = load_spec_filename(spec);
230 document = load_spec_document(spec);
231 uri = load_spec_uri(spec);
232 content_type = load_spec_mime_type(spec);
235 file_name = generate_filename_safely_fn(
236 maybe_filename_from_content_disposition(
237 document && get_document_content_disposition(document),
238 get_charset_for_save(document)) ||
239 ((spec.suggest_filename_from_uri != false) && maybe_filename_from_uri(uri)) ||
240 maybe_filename_from_title(load_spec_title(spec)) ||
241 maybe_filename_from_url_last_directory(uri) ||
242 maybe_filename_from_url_host(uri) ||
243 maybe_filename_from_localization_default() ||
247 var base_name = file_name.replace(/\.[^.]*$/, "");
249 var file_ext = extension || load_spec_filename_extension(spec);
252 file_ext = get_default_extension(file_name, uri, content_type);
253 if (file_ext == "") {
254 let x = file_name.lastIndexOf(".");
258 file_ext = file_name.substring(x+1);
260 if (!file_ext && (/^http(s?)/i).test(uri.scheme) && !content_type ||
261 content_type == "application/octet-stream")
265 if (file_ext != null && file_ext.length > 0)
266 return base_name + "." + file_ext;
271 function suggest_save_path_from_file_name (file_name, buffer) {
272 var cwd = with_current_buffer(buffer, function (I) I.local.cwd);
273 var file = cwd.clone();
274 file.append(file_name);