LauncherGenerator — do not use Guava
[idea/community.git] / tools / launcher-generator / src / com / pme / launcher / LauncherGenerator.java
1 /*
2  * Copyright 2006 ProductiveMe Inc.
3  * Copyright 2013 JetBrains s.r.o.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17
18 package com.pme.launcher;
19
20 import com.pme.exe.ExeFormat;
21 import com.pme.exe.ExeReader;
22 import com.pme.exe.SectionReader;
23 import com.pme.exe.res.DirectoryEntry;
24 import com.pme.exe.res.RawResource;
25 import com.pme.exe.res.ResourceSectionReader;
26 import com.pme.exe.res.StringTableDirectory;
27 import com.pme.exe.res.icon.IconResourceInjector;
28 import com.pme.exe.res.vi.StringTable;
29 import com.pme.exe.res.vi.VersionInfo;
30 import com.pme.util.OffsetTrackingInputStream;
31
32 import java.io.*;
33 import java.nio.file.Files;
34 import java.nio.file.Path;
35 import java.nio.file.StandardCopyOption;
36
37 /**
38  * Date: May 6, 2006
39  * Time: 10:43:01 AM
40  */
41 public class LauncherGenerator {
42   private File myTemplate;
43   private File myExePath;
44   private StringTableDirectory myStringTableDirectory;
45   private DirectoryEntry myRoot;
46   private ExeReader myReader;
47   private VersionInfo myVersionInfo;
48
49   public LauncherGenerator(File template, File exePath) {
50     myTemplate = template;
51     myExePath = exePath;
52   }
53
54   public void load() throws  IOException {
55     RandomAccessFile stream = new RandomAccessFile(myTemplate, "r");
56     ExeReader formatReader = new ExeReader(myTemplate.getName(), ExeFormat.UNKNOWN);
57     formatReader.read(stream);
58     stream.seek(0L);
59     myReader = new ExeReader(myTemplate.getName(), formatReader.getExeFormat());
60     myReader.read(stream);
61     stream.close();
62     SectionReader sectionReader = myReader.getSectionReader(".rsrc");
63     ResourceSectionReader resourceReader = (ResourceSectionReader) sectionReader.getMember(".rsrc");
64     myRoot = resourceReader.getRoot();
65     DirectoryEntry subDir = myRoot.findSubDir("IRD6");
66     myStringTableDirectory = new StringTableDirectory(subDir);
67
68     RawResource versionInfoResource = getVersionInfoResource();
69     ByteArrayInputStream bytesStream = new ByteArrayInputStream(versionInfoResource.getBytes().getBytes());
70
71     myVersionInfo = new VersionInfo();
72     myVersionInfo.read(new OffsetTrackingInputStream(new DataInputStream(bytesStream)));
73   }
74
75   private RawResource getVersionInfoResource() {
76     DirectoryEntry viDir = myRoot.findSubDir("IRD16").findSubDir( "IRD1" );
77     return viDir.getRawResource(0);
78   }
79
80   private void saveVersionInfo() throws IOException {
81     ByteArrayOutputStream baos = new ByteArrayOutputStream();
82     myVersionInfo.resetOffsets(0);
83     myVersionInfo.write(new DataOutputStream(baos));
84     getVersionInfoResource().setBytes(baos.toByteArray());
85   }
86
87   public void generate() throws IOException {
88     myStringTableDirectory.save();
89     saveVersionInfo();
90
91     myReader.resetOffsets(0);
92
93     myExePath.getParentFile().mkdirs();
94     myExePath.createNewFile();
95     RandomAccessFile exeStream = new RandomAccessFile(myExePath, "rw");
96     myReader.write(exeStream);
97     exeStream.close();
98
99 //    verifyVersionInfo();
100   }
101
102   private void verifyVersionInfo() throws IOException {
103     String versionInfoPath = myExePath + ".version";
104     RandomAccessFile versionInfoStream = new RandomAccessFile(versionInfoPath, "rw");
105     try {
106       myVersionInfo.resetOffsets(0);
107       myVersionInfo.write(versionInfoStream);
108     }
109     finally {
110       versionInfoStream.close();
111     }
112
113     VersionInfo copy = new VersionInfo();
114     copy.read(new OffsetTrackingInputStream(new DataInputStream(new FileInputStream(versionInfoPath))));
115   }
116
117   public void setResourceString(int id, String value) {
118     myStringTableDirectory.setString(id, value);
119   }
120
121   public void setVersionInfoString(String key, String value) {
122     StringTable stringTable = myVersionInfo.getStringFileInfo().getFirstStringTable();
123     if (stringTable != null) {
124       stringTable.setStringValue(key, value);
125     }
126   }
127
128   public void injectBitmap(int id, byte[] bitmapFileData) {
129     DirectoryEntry subDirBmp = myRoot.findSubDir("IRD2").findSubDir("IRD" + id);
130     RawResource bmpRes = subDirBmp.getRawResource(0);
131     // strip off BITMAPFILEHEADER
132     byte[] bitmapResourceData = new byte[bitmapFileData.length-14];
133     System.arraycopy(bitmapFileData, 14, bitmapResourceData, 0, bitmapResourceData.length);
134     bmpRes.setBytes(bitmapResourceData);
135   }
136
137   public void injectIcon(int id, final InputStream iconStream) throws IOException {
138     Path f = Files.createTempFile("launcher", "ico");
139     try {
140       Files.copy(iconStream, f, StandardCopyOption.REPLACE_EXISTING);
141     }
142     finally {
143       iconStream.close();
144     }
145     new IconResourceInjector().injectIcon(f.toFile(), myRoot, "IRD" + id);
146   }
147
148   public void setVersionNumber(int majorVersion, int minorVersion, int bugfixVersion) {
149     int mostSignificantVersion = majorVersion << 16 | minorVersion;
150     int leastSignificantVersion = bugfixVersion << 16;
151     myVersionInfo.getFixedFileInfo().setFileVersion(mostSignificantVersion, leastSignificantVersion);
152     myVersionInfo.getFixedFileInfo().setProductVersion(mostSignificantVersion, leastSignificantVersion);
153   }
154 }