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
14 /* maybe_get_filename_extension
16 * file_name_s: string filename, may be null.
18 * returns null or extension part of file_name_s.
20 function maybe_get_filename_extension (file_name_s) {
21 var url = Components.classes["@mozilla.org/network/standard-url;1"]
22 .createInstance(Components.interfaces.nsIURL);
23 url.filePath = file_name_s;
24 if (url.fileExtension == '')
26 return url.fileExtension;
30 function maybe_get_url_extension (url_o) {
32 var url = url_o.QueryInterface(Components.interfaces.nsIURL);
33 if (url.fileExtension == '')
35 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 = Components.classes["@mozilla.org/mime;1"]
58 .getService(Components.interfaces.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 = Components.classes["@mozilla.org/mime;1"]
79 .getService(Components.interfaces.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;
110 function maybe_filename_from_content_disposition (content_disposition, charset) {
111 if (content_disposition) {
112 const mhp = Components.classes["@mozilla.org/network/mime-hdrparam;1"]
113 .getService(Components.interfaces.nsIMIMEHeaderParam);
114 var dummy = { value: null }; // Need an out param...
118 filename = mhp.getParameter(content_disposition, "filename", charset, true, dummy);
121 filename = mhp.getParameter(content_disposition, "name", charset, true, dummy);
132 function maybe_filename_from_uri (uri) {
134 var url = uri.QueryInterface(Components.interfaces.nsIURL);
135 if (url.fileName != "") {
136 // 2) Use the actual file name, if present
137 var text_to_sub_uri = Cc["@mozilla.org/intl/texttosuburi;1"].
138 getService(Ci.nsITextToSubURI);
139 return text_to_sub_uri.unEscapeURIForUI(url.originCharset ||
140 "UTF-8", url.fileName);
143 // This is something like a data: and so forth URI... no filename here.
148 function maybe_filename_from_title (title) {
150 title = title.replace(/^\s+|\s+$/g, "");
151 if (title && title.length > 0) {
152 // 3) Use the document title
159 function maybe_filename_from_url_last_directory (uri) {
160 // 5) If this is a directory, use the last directory name
162 var path = uri.path.match(/\/([^\/]+)\/$/);
163 if (path && path.length > 1)
171 function maybe_filename_from_url_host (uri) {
172 if (uri && 'host' in uri)
177 function maybe_filename_from_localization_default () {
179 return getStringBundle().GetStringFromName("DefaultSaveFileName");
185 function generate_filename_safely_default (filename) {
186 return filename.replace(/[\/]+/g, '_');
189 function generate_filename_safely_darwin (filename) {
190 return filename.replace(/[\:\/]+/g, '_');
193 function generate_filename_safely_winnt (filename) {
194 filename = filename.replace(/[\"]+/g, "'");
195 filename = filename.replace(/[\*\:\?]+/g, ' ');
196 filename = filename.replace(/[\<]+/g, '(');
197 filename = filename.replace(/[\>]+/g, ')');
198 filename = filename.replace(/[\\\/\|]+/g, '_');
203 var generate_filename_safely_fn = null;
207 generate_filename_safely_fn = generate_filename_safely_darwin;
210 generate_filename_safely_fn = generate_filename_safely_winnt;
213 generate_filename_safely_fn = generate_filename_safely_default;
218 * spec may be a string (URI), a load spec, or an nsIDOMDocument
220 * extension may be null, in which case an extension is suggested as well
222 function suggest_file_name (spec, extension) {
227 if (typeof(spec) == "string" || spec instanceof Ci.nsIDOMDocument)
228 spec = load_spec(spec);
230 var file_name = load_spec_filename(spec);
232 document = load_spec_document(spec);
233 uri = load_spec_uri(spec);
234 content_type = load_spec_mime_type(spec);
237 file_name = generate_filename_safely_fn(
238 maybe_filename_from_content_disposition(
239 document && get_document_content_disposition(document),
240 get_charset_for_save(document)) ||
241 ((spec.suggest_filename_from_uri != false) && maybe_filename_from_uri(uri)) ||
242 maybe_filename_from_title(load_spec_title(spec)) ||
243 maybe_filename_from_url_last_directory(uri) ||
244 maybe_filename_from_url_host(uri) ||
245 maybe_filename_from_localization_default() ||
249 var base_name = file_name.replace(/\.[^.]*$/, "");
251 var file_ext = extension || load_spec_filename_extension(spec);
254 file_ext = get_default_extension(file_name, uri, content_type);
255 if (file_ext == "") {
256 let x = file_name.lastIndexOf(".");
260 file_ext = file_name.substring(x+1);
262 if (!file_ext && (/^http(s?)/i).test(uri.scheme) && !content_type ||
263 content_type == "application/octet-stream")
267 if (file_ext != null && file_ext.length > 0)
268 return base_name + "." + file_ext;
273 function suggest_save_path_from_file_name (file_name, buffer) {
274 var cwd = with_current_buffer(buffer, function (I) I.local.cwd);
275 var file = cwd.clone();
276 file.append(file_name);
280 provide("suggest-file-name");