Bug 903174 - Move GonkNativeWindow to /widget/gonk/nativewindow. r=vlad
[gecko.git] / xulrunner / setup / nsXULAppInstall.js
blob7bd11064bb94153bfa15dd5f2f28b47ca83a3abf
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 #filter substitution
3 #if 0
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/. */
7 #endif
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) {
20   try {
21     return Components.classes["@mozilla.org/file/directory_service;1"].
22       getService(Components.interfaces.nsIProperties).
23       get(aKey, nsIFile);
24   }
25   catch (e) {
26     throw "Couln't get directory service key: " + aKey;
27   }
30 function createINIParser(aFile) {
31   return Components.manager.
32     getClassObjectByContractID("@mozilla.org/xpcom/ini-parser-factory;1",
33                                nsIINIParserFactory).
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();
45     ddest.append(leaf);
47     if (f.isDirectory()) {
48       copy_recurse(f, ddest);
49     }
50     else {
51       if (ddest.exists())
52         ddest.remove(false);
54       f.copyTo(aDest, leaf);
55     }
56   }
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);
67   return s;
70 /**
71  * An extractor implements the following prototype:
72  * readonly attribute nsIINIPaser iniParser;
73  * void copyTo(in nsILocalFile root);
74  */
76 function directoryExtractor(aFile) {
77   this.mDirectory = aFile;
80 directoryExtractor.prototype = {
81   mINIParser : null,
83   get iniParser() {
84     if (!this.mINIParser) {
85       var iniFile = this.mDirectory.clone();
86       iniFile.append("application.ini");
88       this.mINIParser = createINIParser(iniFile);
89     }
90     return this.mINIParser;
91   },
93   copyTo : function de_copyTo(aDest) {
94     // Assume the root already exists
95     copy_recurse(this.mDirectory, aDest);
96   }
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 = {
107   mINIParser : null,
109   get iniParser() {
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);
116       try {
117         this.mZipReader.extract("application.ini", f);
118         this.mINIParser = createINIParser(f);
119       }
120       catch (e) {
121         try {
122           f.remove();
123         }
124         catch (ee) { }
126         throw e;
127       }
128       try {
129         f.remove();
130       }
131       catch (e) { }
132     }
133     return this.mINIParser;
134   },
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);
142     }
143   },
145   _installZipEntry : function ze_installZipEntry(aZipReader, aZipEntry,
146                                                  aDestination) {
147     var file = aDestination.clone();
149     var dirs = aZipEntry.split(/\//);
150     var isDirectory = /\/$/.test(aZipEntry);
152     var end = dirs.length;
153     if (!isDirectory)
154       --end;
156     for (var i = 0; i < end; ++i) {
157       file.append(dirs[i]);
158       if (!file.exists()) {
159         file.create(nsIFile.DIRECTORY_TYPE, 0755);
160       }
161     }
163     if (!isDirectory) {
164       file.append(dirs[end]);
165       aZipReader.extract(aZipEntry, file);
166     }
167   }
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}"),
183   /* nsISupports */
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
194     var vendor;
195     try {
196       vendor = iniParser.getString("App", "Vendor");
197     }
198     catch (e) { }
200     if (aDirectory == null) {
201 #ifdef XP_WIN
202       aDirectory = getDirectoryKey("ProgF");
203       if (vendor)
204         aDirectory.append(vendor);
205 #else
206 #ifdef XP_MACOSX
207       aDirectory = getDirectoryKey("LocApp");
208       if (vendor)
209         aDirectory.append(vendor);
210 #else
211       aDirectory = Components.classes["@mozilla.org/file/local;1"].
212         createInstance(nsILocalFile);
213       aDirectory.initWithPath("/usr/local/lib");
214       if (vendor)
215         aDirectory.append(vendor.toLowerCase());
216 #endif
217 #endif
218     }
219     else {
220       aDirectory = aDirectory.clone();
221     }
223     if (!aDirectory.exists()) {
224       aDirectory.create(nsIFile.DIRECTORY_TYPE, 0755);
225     }
227     if (aLeafName == "") {
228 #ifdef XP_MACOSX
229       aLeafName = appName + ".app";
230 #else
231 #ifdef XP_WIN
232       aLeafName = appName;
233 #else
234       aLeafName = appName.toLowerCase();
235 #endif
236 #endif
237     }
239     aDirectory.append(aLeafName);
240     if (!aDirectory.exists()) {
241       aDirectory.create(nsIFile.DIRECTORY_TYPE, 0755);
242     }
244 #ifdef XP_MACOSX
245     aDirectory.append("Contents");
246     if (!aDirectory.exists()) {
247       aDirectory.create(nsIFile.DIRECTORY_TYPE, 0755);
248     }
250     var version = iniParser.getString("App", "Version");
251     var buildID = iniParser.getString("App", "BuildID");
253     var infoString = "";
254     if (vendor) {
255       infoString = vendor + " ";
256     }
257     infoString += appName + " " + version;
259     var plistFile = aDirectory.clone();
260     plistFile.append("Info.plist");
261     var ostream = openFileOutputStream(plistFile);
263     var contents =
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" +
267     "<dict>\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" +
275     "<true/>\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" +
284     "</dict>\n" +
285     "</plist>";
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);
295     ostream.close();
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);
307 #else
308     extractor.copyTo(aDirectory);
310     var xulrunnerBinary = getDirectoryKey("GreD");
311     xulrunnerBinary.append("xulrunner-stub@BIN_SUFFIX@");
313     xulrunnerBinary.copyTo(aDirectory, appName.toLowerCase() + "@BIN_SUFFIX@");
314 #endif
315   }
318 this.NSGetFactory = XPCOMUtils.generateNSGetFactory([AppInstall]);