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
15 * maybe_get_filename_extension
17 * file_name_s: string filename, may be null.
19 * returns null or extension part of file_name_s.
21 function maybe_get_filename_extension (file_name_s) {
22 var url = Cc["@mozilla.org/network/standard-url;1"]
23 .createInstance(Ci.nsIURL);
24 url.filePath = file_name_s;
25 if (url.fileExtension == '')
27 return url.fileExtension;
31 function maybe_get_url_extension (url_o) {
33 var url = url_o.QueryInterface(Ci.nsIURL);
34 if (url.fileExtension == '')
36 return url.fileExtension;
43 * maybe_get_preferred_filename_extension
45 * file_name_s: string filename, may be null.
47 * content_type: string content type, may be null.
49 * returns null, the default extension for the given
50 * content type, or the extension part of file_name_s.
52 function maybe_get_preferred_filename_extension (file_name_s, content_type) {
53 var ext = maybe_get_filename_extension (file_name_s);
58 // throws if content_type is an empty string
59 mimeInfo = Cc["@mozilla.org/mime;1"]
60 .getService(Ci.nsIMIMEService)
61 .getFromTypeAndExtension(content_type, ext);
62 primary = mimeInfo.primaryExtension;
65 if (ext && mimeInfo && mimeInfo.extensionExists(ext))
74 function maybe_get_preferred_url_extension (url_o, content_type) {
75 var ext = maybe_get_url_extension(url_o);
80 mimeInfo = Cc["@mozilla.org/mime;1"]
81 .getService(Ci.nsIMIMEService)
82 .getFromTypeAndExtension(content_type, null);
83 primary = mimeInfo.primaryExtension;
86 if (ext && mimeInfo && mimeInfo.extensionExists(ext))
94 function get_default_extension (file_name_s, url_o, content_type) {
95 if (content_type == "text/plain" ||
96 content_type == "application/octet-stream" ||
97 url_o.scheme == "ftp")
101 return (maybe_get_preferred_filename_extension(file_name_s, content_type) ||
102 maybe_get_preferred_url_extension(url_o, content_type));
105 function get_charset_for_save (doc) {
107 return doc.characterSet;
111 function maybe_filename_from_content_disposition (spec) {
112 var document = load_spec_document(spec);
113 var content_disposition = (document && get_document_content_disposition(document));
114 var charset = get_charset_for_save(document);
115 if (content_disposition) {
116 const mhp = Cc["@mozilla.org/network/mime-hdrparam;1"]
117 .getService(Ci.nsIMIMEHeaderParam);
118 var dummy = { value: null }; // Need an out param...
122 filename = mhp.getParameter(content_disposition, "filename", charset, true, dummy);
125 filename = mhp.getParameter(content_disposition, "name", charset, true, dummy);
136 function maybe_filename_from_uri (spec) {
137 var uri = load_spec_uri(spec);
139 var url = uri.QueryInterface(Ci.nsIURL);
140 if (url.fileName != "") {
141 // 2) Use the actual file name, if present
142 var text_to_sub_uri = Cc["@mozilla.org/intl/texttosuburi;1"].
143 getService(Ci.nsITextToSubURI);
144 return text_to_sub_uri.unEscapeURIForUI(url.originCharset ||
145 "UTF-8", url.fileName);
148 // This is something like a data: and so forth URI... no filename here.
154 * maybe_filename_from_title returns a filename from the load-spec's title
155 * property if and only if the load-spec has neither a document nor an
156 * element property. In those cases, defer to generating the filename
159 function maybe_filename_from_title (spec) {
160 if (load_spec_document(spec) || load_spec_element(spec))
162 var title = load_spec_title(spec);
164 title = trim_whitespace(title);
171 function maybe_filename_from_url_last_directory (spec) {
172 var uri = load_spec_uri(spec);
174 var path = uri.path.match(/\/([^\/]+)\/$/);
175 if (path && path.length > 1)
176 return path[1] + ".";
183 function maybe_filename_from_url_host (spec) {
184 var uri = load_spec_uri(spec);
185 if (uri && 'host' in uri) {
187 return uri.host + ".";
193 function maybe_filename_from_localization_default () {
195 return getStringBundle().GetStringFromName("DefaultSaveFileName");
203 * Sanitize filename for various platforms.
206 function generate_filename_safely_default (filename) {
207 return filename.replace(/[\/]+/g, '_');
210 function generate_filename_safely_darwin (filename) {
211 return filename.replace(/[\:\/]+/g, '_');
214 function generate_filename_safely_winnt (filename) {
215 filename = filename.replace(/[\"]+/g, "'");
216 filename = filename.replace(/[\*\:\?]+/g, ' ');
217 filename = filename.replace(/[\<]+/g, '(');
218 filename = filename.replace(/[\>]+/g, ')');
219 filename = filename.replace(/[\\\/\|]+/g, '_');
224 define_variable("generate_filename_safely_fn",
225 ({ Darwin: generate_filename_safely_darwin,
226 WINNT: generate_filename_safely_winnt }[get_os()]
227 || generate_filename_safely_default),
228 "Function to sanitize the filenames generated by suggest_file_name "+
229 "for the current platform.");
233 * spec may be a string (URI), a load spec, or an nsIDOMDocument
235 * extension may be null, in which case an extension is suggested as well
237 function suggest_file_name (spec, extension) {
238 if (typeof spec == "string" || spec instanceof Ci.nsIDOMDocument)
239 spec = load_spec(spec);
241 var file_name = load_spec_filename(spec);
242 var uri = load_spec_uri(spec);
243 var content_type = load_spec_mime_type(spec);
246 file_name = generate_filename_safely_fn(
247 maybe_filename_from_content_disposition(spec) ||
248 maybe_filename_from_title(spec) ||
249 maybe_filename_from_uri(spec) ||
250 maybe_filename_from_url_last_directory(spec) ||
251 maybe_filename_from_url_host(spec) ||
252 maybe_filename_from_localization_default() ||
255 var base_name = file_name.replace(/\.[^.]*$/, "");
257 var file_ext = extension || load_spec_filename_extension(spec);
260 file_ext = get_default_extension(file_name, uri, content_type);
261 if (file_ext == "") {
262 let x = file_name.lastIndexOf(".");
266 file_ext = file_name.substring(x+1);
268 if (!file_ext && (/^http(s?)/i).test(uri.scheme) && !content_type ||
269 content_type == "application/octet-stream")
275 if (file_ext != null && file_ext.length > 0)
276 return base_name + "." + file_ext;
281 function suggest_save_path_from_file_name (file_name, buffer) {
282 var cwd = with_current_buffer(buffer, function (I) I.local.cwd);
283 var file = cwd.clone();
284 file.append(file_name);
288 provide("suggest-file-name");