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");