001: /*
002: Launch4j (http://launch4j.sourceforge.net/)
003: Cross-platform Java application wrapper for creating Windows native executables.
004:
005: Copyright (c) 2004, 2007 Grzegorz Kowal
006:
007: All rights reserved.
008:
009: Redistribution and use in source and binary forms, with or without modification,
010: are permitted provided that the following conditions are met:
011:
012: * Redistributions of source code must retain the above copyright notice,
013: this list of conditions and the following disclaimer.
014: * Redistributions in binary form must reproduce the above copyright notice,
015: this list of conditions and the following disclaimer in the documentation
016: and/or other materials provided with the distribution.
017: * Neither the name of the Launch4j nor the names of its contributors
018: may be used to endorse or promote products derived from this software without
019: specific prior written permission.
020:
021: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
022: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
023: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
024: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
025: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
026: EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
027: PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
028: PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
029: LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
030: NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
031: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
032: */
033:
034: /*
035: * Created on 2005-04-24
036: */
037: package net.sf.launch4j;
038:
039: import java.io.BufferedWriter;
040: import java.io.File;
041: import java.io.FileWriter;
042: import java.io.IOException;
043: import java.util.List;
044:
045: import net.sf.launch4j.config.Config;
046: import net.sf.launch4j.config.ConfigPersister;
047: import net.sf.launch4j.config.Jre;
048: import net.sf.launch4j.config.Msg;
049: import net.sf.launch4j.config.Splash;
050: import net.sf.launch4j.config.VersionInfo;
051:
052: /**
053: * @author Copyright (C) 2005 Grzegorz Kowal
054: */
055: public class RcBuilder {
056:
057: // winnt.h
058: public static final int LANG_NEUTRAL = 0;
059: public static final int SUBLANG_NEUTRAL = 0;
060: public static final int SUBLANG_DEFAULT = 1;
061: public static final int SUBLANG_SYS_DEFAULT = 2;
062:
063: // MANIFEST
064: public static final int MANIFEST = 1;
065:
066: // ICON
067: public static final int APP_ICON = 1;
068:
069: // BITMAP
070: public static final int SPLASH_BITMAP = 1;
071:
072: // RCDATA
073: public static final int JRE_PATH = 1;
074: public static final int JAVA_MIN_VER = 2;
075: public static final int JAVA_MAX_VER = 3;
076: public static final int SHOW_SPLASH = 4;
077: public static final int SPLASH_WAITS_FOR_WINDOW = 5;
078: public static final int SPLASH_TIMEOUT = 6;
079: public static final int SPLASH_TIMEOUT_ERR = 7;
080: public static final int CHDIR = 8;
081: public static final int SET_PROC_NAME = 9;
082: public static final int ERR_TITLE = 10;
083: public static final int GUI_HEADER_STAYS_ALIVE = 11;
084: public static final int JVM_OPTIONS = 12;
085: public static final int CMD_LINE = 13;
086: public static final int JAR = 14;
087: public static final int MAIN_CLASS = 15;
088: public static final int CLASSPATH = 16;
089: public static final int WRAPPER = 17;
090: public static final int JDK_PREFERENCE = 18;
091: public static final int ENV_VARIABLES = 19;
092: public static final int PRIORITY_CLASS = 20;
093: public static final int DOWNLOAD_URL = 21;
094: public static final int SUPPORT_URL = 22;
095: public static final int MUTEX_NAME = 23;
096: public static final int INSTANCE_WINDOW_TITLE = 24;
097: public static final int INITIAL_HEAP_SIZE = 25;
098: public static final int INITIAL_HEAP_PERCENT = 26;
099: public static final int MAX_HEAP_SIZE = 27;
100: public static final int MAX_HEAP_PERCENT = 28;
101:
102: public static final int STARTUP_ERR = 101;
103: public static final int BUNDLED_JRE_ERR = 102;
104: public static final int JRE_VERSION_ERR = 103;
105: public static final int LAUNCHER_ERR = 104;
106: public static final int INSTANCE_ALREADY_EXISTS_MSG = 105;
107:
108: private final StringBuffer _sb = new StringBuffer();
109:
110: public String getContent() {
111: return _sb.toString();
112: }
113:
114: public String getLine(int line) {
115: return _sb.toString().split("\n")[line - 1];
116: }
117:
118: public File build(Config c) throws IOException {
119: _sb.append("LANGUAGE ");
120: _sb.append(LANG_NEUTRAL);
121: _sb.append(", ");
122: _sb.append(SUBLANG_DEFAULT);
123: _sb.append('\n');
124: addVersionInfo(c.getVersionInfo());
125: addJre(c.getJre());
126: addManifest(MANIFEST, c.getManifest());
127: addIcon(APP_ICON, c.getIcon());
128: addText(ERR_TITLE, c.getErrTitle());
129: addText(DOWNLOAD_URL, c.getDownloadUrl());
130: addText(SUPPORT_URL, c.getSupportUrl());
131: addText(CMD_LINE, c.getCmdLine());
132: addWindowsPath(CHDIR, c.getChdir());
133: addText(PRIORITY_CLASS, String.valueOf(c.getPriorityClass()));
134: addTrue(SET_PROC_NAME, c.isCustomProcName());
135: addTrue(GUI_HEADER_STAYS_ALIVE, c.isStayAlive());
136: addSplash(c.getSplash());
137: addMessages(c);
138:
139: if (c.getSingleInstance() != null) {
140: addText(MUTEX_NAME, c.getSingleInstance().getMutexName());
141: addText(INSTANCE_WINDOW_TITLE, c.getSingleInstance()
142: .getWindowTitle());
143: }
144:
145: if (c.getVariables() != null && !c.getVariables().isEmpty()) {
146: StringBuffer vars = new StringBuffer();
147: append(vars, c.getVariables(), "\t");
148: addText(ENV_VARIABLES, vars.toString());
149: }
150:
151: // MAIN_CLASS / JAR
152: addTrue(WRAPPER, !c.isDontWrapJar());
153: if (c.getClassPath() != null) {
154: addText(MAIN_CLASS, c.getClassPath().getMainClass());
155: addWindowsPath(CLASSPATH, c.getClassPath().getPathsString());
156: }
157: if (c.isDontWrapJar() && c.getJar() != null) {
158: addWindowsPath(JAR, c.getJar().getPath());
159: }
160:
161: File f = Util.createTempFile("rc");
162: BufferedWriter w = new BufferedWriter(new FileWriter(f));
163: w.write(_sb.toString());
164: w.close();
165: return f;
166: }
167:
168: private void addVersionInfo(VersionInfo v) {
169: if (v == null) {
170: return;
171: }
172: _sb.append("1 VERSIONINFO\n");
173: _sb.append("FILEVERSION ");
174: _sb.append(v.getFileVersion().replaceAll("\\.", ", "));
175: _sb.append("\nPRODUCTVERSION ");
176: _sb.append(v.getProductVersion().replaceAll("\\.", ", "));
177: _sb.append("\nFILEFLAGSMASK 0\n" + "FILEOS 0x40000\n"
178: + "FILETYPE 1\n" + "{\n"
179: + " BLOCK \"StringFileInfo\"\n" + " {\n"
180: + " BLOCK \"040904E4\"\n" + // English
181: " {\n");
182: addVerBlockValue("CompanyName", v.getCompanyName());
183: addVerBlockValue("FileDescription", v.getFileDescription());
184: addVerBlockValue("FileVersion", v.getTxtFileVersion());
185: addVerBlockValue("InternalName", v.getInternalName());
186: addVerBlockValue("LegalCopyright", v.getCopyright());
187: addVerBlockValue("OriginalFilename", v.getOriginalFilename());
188: addVerBlockValue("ProductName", v.getProductName());
189: addVerBlockValue("ProductVersion", v.getTxtProductVersion());
190: _sb
191: .append(" }\n }\nBLOCK \"VarFileInfo\"\n{\nVALUE \"Translation\", 0x0409, 0x04E4\n}\n}");
192: }
193:
194: private void addJre(Jre jre) {
195: addWindowsPath(JRE_PATH, jre.getPath());
196: addText(JAVA_MIN_VER, jre.getMinVersion());
197: addText(JAVA_MAX_VER, jre.getMaxVersion());
198: addText(JDK_PREFERENCE, String.valueOf(jre
199: .getJdkPreferenceIndex()));
200: addInteger(INITIAL_HEAP_SIZE, jre.getInitialHeapSize());
201: addInteger(INITIAL_HEAP_PERCENT, jre.getInitialHeapPercent());
202: addInteger(MAX_HEAP_SIZE, jre.getMaxHeapSize());
203: addInteger(MAX_HEAP_PERCENT, jre.getMaxHeapPercent());
204:
205: StringBuffer options = new StringBuffer();
206: if (jre.getOptions() != null && !jre.getOptions().isEmpty()) {
207: addSpace(options);
208: append(options, jre.getOptions(), " ");
209: }
210: addText(JVM_OPTIONS, options.toString());
211: }
212:
213: private void addSplash(Splash splash) {
214: if (splash == null) {
215: return;
216: }
217: addTrue(SHOW_SPLASH, true);
218: addTrue(SPLASH_WAITS_FOR_WINDOW, splash.getWaitForWindow());
219: addText(SPLASH_TIMEOUT, String.valueOf(splash.getTimeout()));
220: addTrue(SPLASH_TIMEOUT_ERR, splash.isTimeoutErr());
221: addBitmap(SPLASH_BITMAP, splash.getFile());
222: }
223:
224: private void addMessages(Config c) {
225: Msg msg = c.getMessages();
226: if (msg == null) {
227: msg = new Msg();
228: }
229: addText(STARTUP_ERR, msg.getStartupErr());
230: addText(BUNDLED_JRE_ERR, msg.getBundledJreErr());
231: addText(JRE_VERSION_ERR, msg.getJreVersionErr());
232: addText(LAUNCHER_ERR, msg.getLauncherErr());
233: if (c.getSingleInstance() != null) {
234: addText(INSTANCE_ALREADY_EXISTS_MSG, msg
235: .getInstanceAlreadyExistsMsg());
236: }
237: }
238:
239: private void append(StringBuffer sb, List list, String separator) {
240: for (int i = 0; i < list.size(); i++) {
241: sb.append(list.get(i));
242: if (i < list.size() - 1) {
243: sb.append(separator);
244: }
245: }
246: }
247:
248: private void addText(int id, String text) {
249: if (text == null || text.equals("")) {
250: return;
251: }
252: _sb.append(id);
253: _sb.append(" RCDATA BEGIN \"");
254: _sb.append(escape(text));
255: _sb.append("\\0\" END\n");
256: }
257:
258: private void addTrue(int id, boolean value) {
259: if (value) {
260: addText(id, "true");
261: }
262: }
263:
264: private void addInteger(int id, Integer value) {
265: if (value != null) {
266: addText(id, value.toString());
267: }
268: }
269:
270: /**
271: * Stores path in Windows format with '\' separators.
272: */
273: private void addWindowsPath(int id, String path) {
274: if (path == null || path.equals("")) {
275: return;
276: }
277: _sb.append(id);
278: _sb.append(" RCDATA BEGIN \"");
279: _sb.append(path.replaceAll("\\\\", "\\\\\\\\").replaceAll("/",
280: "\\\\\\\\"));
281: _sb.append("\\0\" END\n");
282: }
283:
284: private void addManifest(int id, File manifest) {
285: if (manifest == null || manifest.getPath().equals("")) {
286: return;
287: }
288: _sb.append(id);
289: _sb.append(" 24 \"");
290: _sb.append(getPath(Util.getAbsoluteFile(ConfigPersister
291: .getInstance().getConfigPath(), manifest)));
292: _sb.append("\"\n");
293: }
294:
295: private void addIcon(int id, File icon) {
296: if (icon == null || icon.getPath().equals("")) {
297: return;
298: }
299: _sb.append(id);
300: _sb.append(" ICON DISCARDABLE \"");
301: _sb.append(getPath(Util.getAbsoluteFile(ConfigPersister
302: .getInstance().getConfigPath(), icon)));
303: _sb.append("\"\n");
304: }
305:
306: private void addBitmap(int id, File bitmap) {
307: if (bitmap == null) {
308: return;
309: }
310: _sb.append(id);
311: _sb.append(" BITMAP \"");
312: _sb.append(getPath(Util.getAbsoluteFile(ConfigPersister
313: .getInstance().getConfigPath(), bitmap)));
314: _sb.append("\"\n");
315: }
316:
317: private String getPath(File f) {
318: return f.getPath().replaceAll("\\\\", "\\\\\\\\");
319: }
320:
321: private void addSpace(StringBuffer sb) {
322: int len = sb.length();
323: if (len-- > 0 && sb.charAt(len) != ' ') {
324: sb.append(' ');
325: }
326: }
327:
328: private void addVerBlockValue(String key, String value) {
329: _sb.append(" VALUE \"");
330: _sb.append(key);
331: _sb.append("\", \"");
332: if (value != null) {
333: _sb.append(escape(value));
334: }
335: _sb.append("\"\n");
336: }
337:
338: private String escape(String text) {
339: return text.replaceAll("\"", "\"\"");
340: }
341: }
|