1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
9 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
11 const nsIFile = Components.interfaces.nsIFile;
12 const nsIINIParser = Components.interfaces.nsIINIParser;
13 const nsIINIParserFactory = Components.interfaces.nsIINIParserFactory;
14 const nsILocalFile = Components.interfaces.nsILocalFile;
15 const nsISupports = Components.interfaces.nsISupports;
16 const nsIXULAppInstall = Components.interfaces.nsIXULAppInstall;
17 const nsIZipReader = Components.interfaces.nsIZipReader;
19 function getDirectoryKey(aKey) {
21 return Components.classes["@mozilla.org/file/directory_service;1"].
22 getService(Components.interfaces.nsIProperties).
26 throw "Couln't get directory service key: " + aKey;
30 function createINIParser(aFile) {
31 return Components.manager.
32 getClassObjectByContractID("@mozilla.org/xpcom/ini-parser-factory;1",
34 createINIParser(aFile);
37 function copy_recurse(aSource, aDest) {
38 var e = aSource.directoryEntries;
40 while (e.hasMoreElements()) {
41 var f = e.getNext().QueryInterface(nsIFile);
42 var leaf = f.leafName;
44 var ddest = aDest.clone();
47 if (f.isDirectory()) {
48 copy_recurse(f, ddest);
54 f.copyTo(aDest, leaf);
59 const PR_WRONLY = 0x02;
60 const PR_CREATE_FILE = 0x08;
61 const PR_TRUNCATE = 0x20;
63 function openFileOutputStream(aFile) {
64 var s = Components.classes["@mozilla.org/network/file-output-stream;1"].
65 createInstance(Components.interfaces.nsIFileOutputStream);
66 s.init(aFile, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0644, 0);
71 * An extractor implements the following prototype:
72 * readonly attribute nsIINIPaser iniParser;
73 * void copyTo(in nsILocalFile root);
76 function directoryExtractor(aFile) {
77 this.mDirectory = aFile;
80 directoryExtractor.prototype = {
84 if (!this.mINIParser) {
85 var iniFile = this.mDirectory.clone();
86 iniFile.append("application.ini");
88 this.mINIParser = createINIParser(iniFile);
90 return this.mINIParser;
93 copyTo : function de_copyTo(aDest) {
94 // Assume the root already exists
95 copy_recurse(this.mDirectory, aDest);
99 function zipExtractor(aFile) {
100 this.mZipReader = Components.classes["@mozilla.org/libjar/zip-reader;1"].
101 createInstance(nsIZipReader);
102 this.mZipReader.open(aFile);
103 this.mZipReader.test(null);
106 zipExtractor.prototype = {
110 if (!this.mINIParser) {
111 // XXXbsmedberg: this is not very unique, guessing could be a problem
112 var f = getDirectoryKey("TmpD");
113 f.append("application.ini");
114 f.createUnique(nsIFile.NORMAL_FILE_TYPE, 0600);
117 this.mZipReader.extract("application.ini", f);
118 this.mINIParser = createINIParser(f);
133 return this.mINIParser;
136 copyTo : function ze_CopyTo(aDest) {
137 var entries = this.mZipReader.findEntries(null);
138 while (entries.hasMore()) {
139 var entryName = entries.getNext();
141 this._installZipEntry(this.mZipReader, entryName, aDest);
145 _installZipEntry : function ze_installZipEntry(aZipReader, aZipEntry,
147 var file = aDestination.clone();
149 var dirs = aZipEntry.split(/\//);
150 var isDirectory = /\/$/.test(aZipEntry);
152 var end = dirs.length;
156 for (var i = 0; i < end; ++i) {
157 file.append(dirs[i]);
158 if (!file.exists()) {
159 file.create(nsIFile.DIRECTORY_TYPE, 0755);
164 file.append(dirs[end]);
165 aZipReader.extract(aZipEntry, file);
170 function createExtractor(aFile) {
171 if (aFile.isDirectory())
172 return new directoryExtractor(aFile);
174 return new zipExtractor(aFile);
177 function AppInstall() {
180 AppInstall.prototype = {
181 classID: Components.ID("{00790a19-27e2-4d9a-bef0-244080feabfd}"),
184 QueryInterface : XPCOMUtils.generateQI([nsIXULAppInstall]),
186 /* nsIXULAppInstall */
187 installApplication : function ai_IA(aAppFile, aDirectory, aLeafName) {
188 var extractor = createExtractor(aAppFile);
189 var iniParser = extractor.iniParser;
191 var appName = iniParser.getString("App", "Name");
193 // vendor is optional
196 vendor = iniParser.getString("App", "Vendor");
200 if (aDirectory == null) {
202 aDirectory = getDirectoryKey("ProgF");
204 aDirectory.append(vendor);
207 aDirectory = getDirectoryKey("LocApp");
209 aDirectory.append(vendor);
211 aDirectory = Components.classes["@mozilla.org/file/local;1"].
212 createInstance(nsILocalFile);
213 aDirectory.initWithPath("/usr/local/lib");
215 aDirectory.append(vendor.toLowerCase());
220 aDirectory = aDirectory.clone();
223 if (!aDirectory.exists()) {
224 aDirectory.create(nsIFile.DIRECTORY_TYPE, 0755);
227 if (aLeafName == "") {
229 aLeafName = appName + ".app";
234 aLeafName = appName.toLowerCase();
239 aDirectory.append(aLeafName);
240 if (!aDirectory.exists()) {
241 aDirectory.create(nsIFile.DIRECTORY_TYPE, 0755);
245 aDirectory.append("Contents");
246 if (!aDirectory.exists()) {
247 aDirectory.create(nsIFile.DIRECTORY_TYPE, 0755);
250 var version = iniParser.getString("App", "Version");
251 var buildID = iniParser.getString("App", "BuildID");
255 infoString = vendor + " ";
257 infoString += appName + " " + version;
259 var plistFile = aDirectory.clone();
260 plistFile.append("Info.plist");
261 var ostream = openFileOutputStream(plistFile);
264 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
265 "<!DOCTYPE plist PUBLIC \"-//Apple Computer//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n" +
266 "<plist version=\"1.0\">\n" +
268 "<key>CFBundleInfoDictionaryVersion</key>\n" +
269 "<string>6.0</string>\n" +
270 "<key>CFBundlePackageType</key>\n" +
271 "<string>APPL</string>\n" +
272 "<key>CFBundleExecutable</key>\n" +
273 "<string>xulrunner</string>\n" +
274 "<key>NSAppleScriptEnabled</key>\n" +
276 "<key>CFBundleGetInfoString</key>\n" +
277 "<string>" + infoString + "</string>\n" +
278 "<key>CFBundleName</key>\n" +
279 "<string>" + appName + "</string>\n" +
280 "<key>CFBundleShortVersionString</key>\n" +
281 "<string>" + version + "</string>\n" +
282 "<key>CFBundleVersion</key>\n" +
283 "<string>" + version + "." + buildID + "</string>\n" +
287 // "<key>CFBundleIdentifier</key>\n" +
288 // "<string>org.%s.%s</string>\n" +
289 // "<key>CFBundleSignature</key>\n" +
290 // "<string>MOZB</string>\n" +
291 // "<key>CFBundleIconFile</key>\n" +
292 // "<string>document.icns</string>\n" +
294 ostream.write(contents, contents.length);
297 var contentsDir = aDirectory.clone();
298 contentsDir.append("MacOS");
300 var xulrunnerBinary = getDirectoryKey("GreD");
301 xulrunnerBinary.append("xulrunner");
303 xulrunnerBinary.copyTo(contentsDir, "xulrunner");
305 aDirectory.append("Resources");
306 extractor.copyTo(aDirectory);
308 extractor.copyTo(aDirectory);
310 var xulrunnerBinary = getDirectoryKey("GreD");
311 xulrunnerBinary.append("xulrunner-stub@BIN_SUFFIX@");
313 xulrunnerBinary.copyTo(aDirectory, appName.toLowerCase() + "@BIN_SUFFIX@");
318 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AppInstall]);