1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.github.maven_nar.cpptasks.platforms;
21
22 import java.io.BufferedWriter;
23 import java.io.ByteArrayInputStream;
24 import java.io.ByteArrayOutputStream;
25 import java.io.File;
26 import java.io.FileInputStream;
27 import java.io.FileOutputStream;
28 import java.io.IOException;
29 import java.io.InputStream;
30 import java.io.OutputStreamWriter;
31 import java.io.Writer;
32
33 import com.github.maven_nar.cpptasks.CUtil;
34 import com.github.maven_nar.cpptasks.TargetMatcher;
35 import com.github.maven_nar.cpptasks.VersionInfo;
36 import com.github.maven_nar.cpptasks.compiler.LinkType;
37
38
39
40
41
42
43 public final class WindowsPlatform {
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 public static void addVersionFiles(final VersionInfo versionInfo, final LinkType linkType, final File outputFile,
65 final boolean isDebug, final File objDir, final TargetMatcher matcher) throws IOException {
66 if (versionInfo == null) {
67 throw new NullPointerException("versionInfo");
68 }
69 if (linkType == null) {
70 throw new NullPointerException("linkType");
71 }
72 if (outputFile == null) {
73 throw new NullPointerException("outputFile");
74 }
75 if (objDir == null) {
76 throw new NullPointerException("objDir");
77 }
78
79
80
81
82 final VersionInfo mergedInfo = versionInfo.merge();
83
84 final File versionResource = new File(objDir, "versioninfo.rc");
85
86 boolean notChanged = false;
87
88
89
90 if (versionResource.exists()) {
91 final ByteArrayOutputStream memStream = new ByteArrayOutputStream();
92 final Writer writer = new BufferedWriter(new OutputStreamWriter(memStream));
93 writeResource(writer, mergedInfo, outputFile, isDebug, linkType);
94 writer.close();
95 final ByteArrayInputStream proposedResource = new ByteArrayInputStream(memStream.toByteArray());
96
97 final InputStream existingResource = new FileInputStream(versionResource);
98
99
100
101 notChanged = hasSameContent(proposedResource, existingResource);
102 existingResource.close();
103 }
104
105
106
107
108
109 if (!notChanged) {
110 final Writer writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(versionResource)));
111 writeResource(writer, mergedInfo, outputFile, isDebug, linkType);
112 writer.close();
113 }
114 if (matcher != null) {
115 matcher.visit(new File(versionResource.getParent()), versionResource.getName());
116 }
117
118 }
119
120
121
122
123
124
125
126
127
128 private static void encodeVersion(final StringBuffer buf, final short[] version) {
129 for (int i = 0; i < 3; i++) {
130 buf.append(Short.toString(version[i]));
131 buf.append(',');
132 }
133 buf.append(Short.toString(version[3]));
134 }
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149 private static boolean hasSameContent(final InputStream stream1, final InputStream stream2) throws IOException {
150 int byte1 = -1;
151 int byte2 = -1;
152 do {
153 byte1 = stream1.read();
154 byte2 = stream2.read();
155
156 } while (byte1 == byte2 && byte1 != -1);
157 return byte1 == byte2;
158 }
159
160
161
162
163
164
165
166
167 public static short[] parseVersion(final String version) {
168 final short[] values = new short[] {
169 0, 0, 0, 0
170 };
171 if (version != null) {
172 final StringBuffer buf = new StringBuffer(version);
173 int start = 0;
174 for (int i = 0; i < 4; i++) {
175 int end = version.indexOf('.', start);
176 if (end <= 0) {
177 end = version.length();
178 for (int j = end; j > start; j--) {
179 final String part = buf.substring(start, end);
180 try {
181 values[i] = Short.parseShort(part);
182 break;
183 } catch (final NumberFormatException ex) {
184 values[i] = 0;
185 }
186 }
187 break;
188 } else {
189 final String part = buf.substring(start, end);
190 try {
191 values[i] = Short.parseShort(part);
192 start = end + 1;
193 } catch (final NumberFormatException ex) {
194 break;
195 }
196 }
197 }
198 }
199 return values;
200 }
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218 public static void writeResource(final Writer writer, final VersionInfo versionInfo, final File outputFile,
219 final boolean isDebug, final LinkType linkType) throws IOException {
220
221
222
223 writer.write("VS_VERSION_INFO VERSIONINFO\n");
224 final StringBuffer buf = new StringBuffer("FILEVERSION ");
225 encodeVersion(buf, parseVersion(versionInfo.getFileversion()));
226 buf.append("\nPRODUCTVERSION ");
227 encodeVersion(buf, parseVersion(versionInfo.getProductversion()));
228 buf.append("\n");
229 writer.write(buf.toString());
230 buf.setLength(0);
231 buf.append("FILEFLAGSMASK 0x1L /* VS_FF_DEBUG */");
232 final Boolean patched = versionInfo.getPatched();
233 final Boolean prerelease = versionInfo.getPrerelease();
234 if (patched != null) {
235 buf.append(" | 0x4L /* VS_FF_PATCHED */");
236 }
237 if (prerelease != null) {
238 buf.append(" | 0x2L /* VS_FF_PRERELEASE */");
239 }
240 if (versionInfo.getPrivatebuild() != null) {
241 buf.append(" | 0x8L /* VS_FF_PRIVATEBUILD */");
242 }
243 if (versionInfo.getSpecialbuild() != null) {
244 buf.append(" | 0x20L /* VS_FF_SPECIALBUILD */");
245 }
246 buf.append('\n');
247 writer.write(buf.toString());
248 buf.setLength(0);
249 buf.append("FILEFLAGS ");
250
251 if (isDebug) {
252 buf.append("0x1L /* VS_FF_DEBUG */ | ");
253 }
254 if (Boolean.TRUE.equals(patched)) {
255 buf.append("0x4L /* VS_FF_PATCHED */ | ");
256 }
257 if (Boolean.TRUE.equals(prerelease)) {
258 buf.append("0x2L /* VS_FF_PRERELEASE */ | ");
259 }
260
261 if (Boolean.TRUE.equals(versionInfo.getPrivatebuild())) {
262 buf.append("0x8L /* VS_FF_PRIVATEBUILD */ | ");
263 }
264
265 if (Boolean.TRUE.equals(versionInfo.getSpecialbuild())) {
266 buf.append("0x20L /* VS_FF_SPECIALBUILD */ | ");
267 }
268 if (buf.length() > 10) {
269 buf.setLength(buf.length() - 3);
270 buf.append('\n');
271 } else {
272 buf.append("0\n");
273 }
274 writer.write(buf.toString());
275 buf.setLength(0);
276
277 writer.write("FILEOS 0x40004 /* VOS_NT_WINDOWS32 */\nFILETYPE ");
278 if (linkType.isExecutable()) {
279 writer.write("0x1L /* VFT_APP */\n");
280 } else {
281 if (linkType.isSharedLibrary()) {
282 writer.write("0x2L /* VFT_DLL */\n");
283 } else if (linkType.isStaticLibrary()) {
284 writer.write("0x7L /* VFT_STATIC_LIB */\n");
285 } else {
286 writer.write("0x0L /* VFT_UNKNOWN */\n");
287 }
288 }
289 writer.write("FILESUBTYPE 0x0L\n");
290 writer.write("BEGIN\n");
291 writer.write("BLOCK \"StringFileInfo\"\n");
292 writer.write(" BEGIN\n#ifdef UNICODE\nBLOCK \"040904B0\"\n");
293 writer.write("#else\nBLOCK \"040904E4\"\n#endif\n");
294 writer.write("BEGIN\n");
295 if (versionInfo.getFilecomments() != null) {
296 writer.write("VALUE \"Comments\", \"");
297 writer.write(versionInfo.getFilecomments());
298 writer.write("\\0\"\n");
299 }
300 if (versionInfo.getCompanyname() != null) {
301 writer.write("VALUE \"CompanyName\", \"");
302 writer.write(versionInfo.getCompanyname());
303 writer.write("\\0\"\n");
304 }
305 if (versionInfo.getFiledescription() != null) {
306 writer.write("VALUE \"FileDescription\", \"");
307 writer.write(versionInfo.getFiledescription());
308 writer.write("\\0\"\n");
309 }
310 if (versionInfo.getFileversion() != null) {
311 writer.write("VALUE \"FileVersion\", \"");
312 writer.write(versionInfo.getFileversion());
313 writer.write("\\0\"\n");
314 }
315 final String baseName = CUtil.getBasename(outputFile);
316 String internalName = versionInfo.getInternalname();
317 if (internalName == null) {
318 internalName = baseName;
319 }
320 writer.write("VALUE \"InternalName\", \"");
321 writer.write(internalName);
322 writer.write("\\0\"\n");
323 if (versionInfo.getLegalcopyright() != null) {
324 writer.write("VALUE \"LegalCopyright\", \"");
325 writer.write(versionInfo.getLegalcopyright());
326 writer.write("\\0\"\n");
327 }
328 if (versionInfo.getLegaltrademarks() != null) {
329 writer.write("VALUE \"LegalTrademarks\", \"");
330 writer.write(versionInfo.getLegaltrademarks());
331 writer.write("\\0\"\n");
332 }
333 writer.write("VALUE \"OriginalFilename\", \"");
334 writer.write(baseName);
335 writer.write("\\0\"\n");
336 if (versionInfo.getPrivatebuild() != null) {
337 writer.write("VALUE \"PrivateBuild\", \"");
338 writer.write(versionInfo.getPrivatebuild());
339 writer.write("\\0\"\n");
340 }
341 if (versionInfo.getProductname() != null) {
342 writer.write("VALUE \"ProductName\", \"");
343 writer.write(versionInfo.getProductname());
344 writer.write("\\0\"\n");
345 }
346 if (versionInfo.getProductversion() != null) {
347 writer.write("VALUE \"ProductVersion\", \"");
348 writer.write(versionInfo.getProductversion());
349 writer.write("\\0\"\n");
350 }
351 if (versionInfo.getSpecialbuild() != null) {
352 writer.write("VALUE \"SpecialBuild\", \"");
353 writer.write(versionInfo.getSpecialbuild());
354 writer.write("\\0\"\n");
355 }
356 writer.write("END\n");
357 writer.write("END\n");
358
359 writer.write("BLOCK \"VarFileInfo\"\n");
360 writer.write("BEGIN\n#ifdef UNICODE\n");
361 writer.write("VALUE \"Translation\", 0x409, 1200\n");
362 writer.write("#else\n");
363 writer.write("VALUE \"Translation\", 0x409, 1252\n");
364 writer.write("#endif\n");
365 writer.write("END\n");
366 writer.write("END\n");
367 }
368
369
370
371
372 private WindowsPlatform() {
373 }
374
375 }