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
)
50 var ext
= maybe_get_filename_extension (file_name_s
);
55 // throws if content_type is an empty string
56 mimeInfo
= Components
.classes
["@mozilla.org/mime;1"]
57 .getService(Components
.interfaces
.nsIMIMEService
)
58 .getFromTypeAndExtension(content_type
, ext
);
59 primary
= mimeInfo
.primaryExtension
;
62 if (ext
&& mimeInfo
&& mimeInfo
.extensionExists (ext
))
71 function maybe_get_preferred_url_extension (url_o
, content_type
) {
72 var ext
= maybe_get_url_extension (url_o
);
77 mimeInfo
= Components
.classes
["@mozilla.org/mime;1"]
78 .getService(Components
.interfaces
.nsIMIMEService
)
79 .getFromTypeAndExtension(content_type
, null);
80 primary
= mimeInfo
.primaryExtension
;
83 if (ext
&& mimeInfo
&& mimeInfo
.extensionExists (ext
))
91 function get_default_extension (file_name_s
, url_o
, content_type
) {
92 if (content_type
== "text/plain" ||
93 content_type
== "application/octet-stream" ||
94 url_o
.scheme
== "ftp")
98 return (maybe_get_preferred_filename_extension (file_name_s
, content_type
) ||
99 maybe_get_preferred_url_extension (url_o
, content_type
));
102 function get_charset_for_save(aDocument
)
105 return aDocument
.characterSet
;
110 function maybe_filename_from_content_disposition (aContentDisposition
, charset
) {
111 if (aContentDisposition
) {
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(aContentDisposition
, "filename", charset
, true, dummy
);
121 fileName
= mhp
.getParameter(aContentDisposition
, "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 textToSubURI
= Cc
["@mozilla.org/intl/texttosuburi;1"].getService(Ci
.nsITextToSubURI
);
138 return textToSubURI
.unEscapeURIForUI(url
.originCharset
|| "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 var docTitle
= title
.replace(/^\s+|\s+$/g, "");
149 if (docTitle
&& docTitle
.length
> 0) {
150 // 3) Use the document title
157 function maybe_filename_from_url_last_directory (aURI
) {
158 // 5) If this is a directory, use the last directory name
160 var path
= aURI
.path
.match(/\/([^\/]+)\/$/);
161 if (path
&& path
.length
> 1)
169 function maybe_filename_from_url_host (aURI
) {
170 if (aURI
&& 'host' in aURI
)
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
)
193 filename
= filename
.replace (/[\"]+/g, "'");
194 filename
= filename
.replace (/[\*\:\?]+/g, ' ');
195 filename
= filename
.replace (/[\<]+/g, '(');
196 filename
= filename
.replace (/[\>]+/g, ')');
197 filename
= filename
.replace (/[\\\/\|]+/g, '_');
202 var generate_filename_safely_fn
= null;
206 generate_filename_safely_fn
= generate_filename_safely_darwin
;
209 generate_filename_safely_fn
= generate_filename_safely_winnt
;
212 generate_filename_safely_fn
= generate_filename_safely_default
;
217 * spec may be a string (URI), a load spec, or an nsIDOMDocument
219 * extension may be null, in which case an extension is suggested as well
221 function suggest_file_name(spec
, extension
) {
226 if (spec
instanceof Ci
.nsIDOMDocument
)
227 spec
= {document
: spec
};
229 var file_name
= load_spec_filename(spec
);
231 document
= load_spec_document(spec
);
232 uri
= load_spec_uri(spec
);
233 content_type
= load_spec_mime_type(spec
);
236 file_name
= generate_filename_safely_fn(
237 maybe_filename_from_content_disposition(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
= (buffer
&& buffer
.cwd
) || default_directory
.path
;
273 var file
= get_file(cwd
);
274 file
.append(file_name
);