1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
4 /* ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is Mozilla XULRunner.
19 * The Initial Developer of the Original Code is
20 * Benjamin Smedberg <benjamin@smedbergs.us>
22 * Portions created by the Initial Developer are Copyright (C) 2005
23 * the Mozilla Foundation <http://www.mozilla.org/>. All Rights Reserved.
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
42 const nsIFile
= Components
.interfaces
.nsIFile
;
43 const nsIINIParser
= Components
.interfaces
.nsIINIParser
;
44 const nsIINIParserFactory
= Components
.interfaces
.nsIINIParserFactory
;
45 const nsILocalFile
= Components
.interfaces
.nsILocalFile
;
46 const nsISupports
= Components
.interfaces
.nsISupports
;
47 const nsIXULAppInstall
= Components
.interfaces
.nsIXULAppInstall
;
48 const nsIZipReader
= Components
.interfaces
.nsIZipReader
;
50 function getDirectoryKey(aKey
) {
52 return Components
.classes
["@mozilla.org/file/directory_service;1"].
53 getService(Components
.interfaces
.nsIProperties
).
57 throw "Couln't get directory service key: " + aKey
;
61 function createINIParser(aFile
) {
62 return Components
.manager
.
63 getClassObjectByContractID("@mozilla.org/xpcom/ini-parser-factory;1",
65 createINIParser(aFile
);
68 function copy_recurse(aSource
, aDest
) {
69 var e
= aSource
.directoryEntries
;
71 while (e
.hasMoreElements()) {
72 var f
= e
.getNext().QueryInterface(nsIFile
);
73 var leaf
= f
.leafName
;
75 var ddest
= aDest
.clone();
78 if (f
.isDirectory()) {
79 copy_recurse(f
, ddest
);
85 f
.copyTo(aDest
, leaf
);
90 const PR_WRONLY
= 0x02;
91 const PR_CREATE_FILE
= 0x08;
92 const PR_TRUNCATE
= 0x20;
94 function openFileOutputStream(aFile
) {
95 var s
= Components
.classes
["@mozilla.org/network/file-output-stream;1"].
96 createInstance(Components
.interfaces
.nsIFileOutputStream
);
97 s
.init(aFile
, PR_WRONLY
| PR_CREATE_FILE
| PR_TRUNCATE
, 0644, 0);
102 * An extractor implements the following prototype:
103 * readonly attribute nsIINIPaser iniParser;
104 * void copyTo(in nsILocalFile root);
107 function directoryExtractor(aFile
) {
108 this.mDirectory
= aFile
;
111 directoryExtractor
.prototype = {
115 if (!this.mINIParser
) {
116 var iniFile
= this.mDirectory
.clone();
117 iniFile
.append("application.ini");
119 this.mINIParser
= createINIParser(iniFile
);
121 return this.mINIParser
;
124 copyTo
: function de_copyTo(aDest
) {
125 // Assume the root already exists
126 copy_recurse(this.mDirectory
, aDest
);
130 function zipExtractor(aFile
) {
131 this.mZipReader
= Components
.classes
["@mozilla.org/libjar/zip-reader;1"].
132 createInstance(nsIZipReader
);
133 this.mZipReader
.open(aFile
);
134 this.mZipReader
.test(null);
137 zipExtractor
.prototype = {
141 if (!this.mINIParser
) {
142 // XXXbsmedberg: this is not very unique, guessing could be a problem
143 var f
= getDirectoryKey("TmpD");
144 f
.append("application.ini");
145 f
.createUnique(nsIFile
.NORMAL_FILE_TYPE
, 0600);
148 this.mZipReader
.extract("application.ini", f
);
149 this.mINIParser
= createINIParser(f
);
164 return this.mINIParser
;
167 copyTo
: function ze_CopyTo(aDest
) {
168 var entries
= this.mZipReader
.findEntries(null);
169 while (entries
.hasMore()) {
170 var entryName
= entries
.getNext();
172 this._installZipEntry(this.mZipReader
, entryName
, aDest
);
176 _installZipEntry
: function ze_installZipEntry(aZipReader
, aZipEntry
,
178 var file
= aDestination
.clone();
180 var dirs
= aZipEntry
.split(/\//);
181 var isDirectory
= /\/$/.test(aZipEntry
);
183 var end
= dirs
.length
;
187 for (var i
= 0; i
< end
; ++i
) {
188 file
.append(dirs
[i
]);
189 if (!file
.exists()) {
190 file
.create(nsIFile
.DIRECTORY_TYPE
, 0755);
195 file
.append(dirs
[end
]);
196 aZipReader
.extract(aZipEntry
, file
);
201 function createExtractor(aFile
) {
202 if (aFile
.isDirectory())
203 return new directoryExtractor(aFile
);
205 return new zipExtractor(aFile
);
211 QueryInterface
: function ai_QI(iid
) {
212 if (iid
.equals(nsIXULAppInstall
) ||
213 iid
.equals(nsISupports
))
216 throw Components
.result
.NS_ERROR_NO_INTERFACE
;
219 /* nsIXULAppInstall */
220 installApplication
: function ai_IA(aAppFile
, aDirectory
, aLeafName
) {
221 var extractor
= createExtractor(aAppFile
);
222 var iniParser
= extractor
.iniParser
;
224 var appName
= iniParser
.getString("App", "Name");
226 // vendor is optional
229 vendor
= iniParser
.getString("App", "Vendor");
233 if (aDirectory
== null) {
235 aDirectory
= getDirectoryKey("ProgF");
237 aDirectory
.append(vendor
);
240 aDirectory
= getDirectoryKey("LocApp");
242 aDirectory
.append(vendor
);
244 aDirectory
= Components
.classes
["@mozilla.org/file/local;1"].
245 createInstance(nsILocalFile
);
246 aDirectory
.initWithPath("/usr/lib");
248 aDirectory
.append(vendor
.toLowerCase());
253 aDirectory
= aDirectory
.clone();
256 if (!aDirectory
.exists()) {
257 aDirectory
.create(nsIFile
.DIRECTORY_TYPE
, 0755);
260 if (aLeafName
== "") {
262 aLeafName
= appName
+ ".app";
267 aLeafName
= appName
.toLowerCase();
272 aDirectory
.append(aLeafName
);
273 if (!aDirectory
.exists()) {
274 aDirectory
.create(nsIFile
.DIRECTORY_TYPE
, 0755);
278 aDirectory
.append("Contents");
279 if (!aDirectory
.exists()) {
280 aDirectory
.create(nsIFile
.DIRECTORY_TYPE
, 0755);
283 var version
= iniParser
.getString("App", "Version");
284 var buildID
= iniParser
.getString("App", "BuildID");
288 infoString
= vendor
+ " ";
290 infoString
+= appName
+ " " + version
;
292 var plistFile
= aDirectory
.clone();
293 plistFile
.append("Info.plist");
294 var ostream
= openFileOutputStream(plistFile
);
297 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
298 "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" +
299 "<plist version=\"1.0\">\n" +
301 "<key>CFBundleInfoDictionaryVersion</key>\n" +
302 "<string>6.0</string>\n" +
303 "<key>CFBundlePackageType</key>\n" +
304 "<string>APPL</string>\n" +
305 "<key>CFBundleExecutable</key>\n" +
306 "<string>xulrunner</string>\n" +
307 "<key>NSAppleScriptEnabled</key>\n" +
309 "<key>CFBundleGetInfoString</key>\n" +
310 "<string>" + infoString
+ "</string>\n" +
311 "<key>CFBundleName</key>\n" +
312 "<string>" + appName
+ "</string>\n" +
313 "<key>CFBundleShortVersionString</key>\n" +
314 "<string>" + version
+ "</string>\n" +
315 "<key>CFBundleVersion</key>\n" +
316 "<string>" + version
+ "." + buildID
+ "</string>\n" +
320 // "<key>CFBundleIdentifier</key>\n" +
321 // "<string>org.%s.%s</string>\n" +
322 // "<key>CFBundleSignature</key>\n" +
323 // "<string>MOZB</string>\n" +
324 // "<key>CFBundleIconFile</key>\n" +
325 // "<string>document.icns</string>\n" +
327 ostream
.write(contents
, contents
.length
);
330 var contentsDir
= aDirectory
.clone();
331 contentsDir
.append("MacOS");
333 var xulrunnerBinary
= getDirectoryKey("XCurProcD");
334 xulrunnerBinary
.append("xulrunner");
336 xulrunnerBinary
.copyTo(contentsDir
, "xulrunner");
338 aDirectory
.append("Resources");
339 extractor
.copyTo(aDirectory
);
341 extractor
.copyTo(aDirectory
);
343 var xulrunnerBinary
= getDirectoryKey("XCurProcD");
344 xulrunnerBinary
.append("xulrunner-stub@BIN_SUFFIX@");
346 xulrunnerBinary
.copyTo(aDirectory
, appName
.toLowerCase() + "@BIN_SUFFIX@");
351 const AppInstallFactory
= {
353 QueryInterface
: function aif_QI(iid
) {
354 if (iid
.equals(Components
.interfaces
.nsIFactory
) ||
355 iid
.equals(nsISupports
))
358 throw Components
.results
.NS_ERROR_NO_INTERFACE
;
362 createInstance
: function aif_CI(aOuter
, aIID
) {
364 throw Components
.results
.NS_ERROR_NO_AGGREGATION
;
366 return AppInstall
.QueryInterface(aIID
);
369 lockFactory
: function aif_lock(aLock
) { }
372 const AppInstallContractID
= "@mozilla.org/xulrunner/app-install-service;1";
373 const AppInstallCID
= Components
.ID("{00790a19-27e2-4d9a-bef0-244080feabfd}");
375 const AppInstallModule
= {
377 QueryInterface
: function mod_QI(iid
) {
378 if (iid
.equals(Components
.interfaces
.nsIModule
) ||
379 iid
.equals(nsISupports
))
382 throw Components
.results
.NS_ERROR_NO_INTERFACE
;
386 getClassObject
: function mod_gco(aCompMgr
, aClass
, aIID
) {
387 if (aClass
.equals(AppInstallCID
))
388 return AppInstallFactory
.QueryInterface(aIID
);
390 return Components
.results
.NS_ERROR_FACTORY_NOT_REGISTERED
;
393 registerSelf
: function mod_regself(aCompMgr
, aLocation
,
395 var reg
= aCompMgr
.QueryInterface(Components
.interfaces
.nsIComponentRegistrar
);
396 reg
.registerFactoryLocation(AppInstallCID
,
398 AppInstallContractID
,
404 unregisterSelf
: function mod_unreg(aCompMgr
, aLocation
, aLoaderStr
) {
405 var reg
= aCompMgr
.QueryInterface(Components
.interfaces
.nsIComponentRegistrar
);
406 reg
.unregisterFactoryLocation(AppInstallCID
,
410 canUnload
: function mod_unload(aCompMgr
) {
415 function NSGetModule(compMgr
, fileSpec
) {
416 return AppInstallModule
;