11/*
2- * Copyright (c) 2019, 2024 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2019, 2025 , Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
@@ -56,36 +56,56 @@ public enum WixTool {
5656 this .minimalVersion = minimalVersion ;
5757 }
5858
59- static final class ToolInfo {
59+ interface ToolInfo {
60+ Path path ();
61+ DottedVersion version ();
62+ }
63+
64+ interface CandleInfo extends ToolInfo {
65+ boolean fips ();
66+ }
6067
61- ToolInfo (Path path , String version ) {
62- this .path = path ;
63- this .version = DottedVersion .lazy (version );
68+ private record DefaultToolInfo (Path path , DottedVersion version ) implements ToolInfo {
69+ DefaultToolInfo {
70+ Objects .requireNonNull (path );
71+ Objects .requireNonNull (version );
6472 }
6573
66- final Path path ;
67- final DottedVersion version ;
74+ DefaultToolInfo (Path path , String version ) {
75+ this (path , DottedVersion .lazy (version ));
76+ }
77+ }
78+
79+ private record DefaultCandleInfo (Path path , DottedVersion version , boolean fips ) implements CandleInfo {
80+ DefaultCandleInfo {
81+ Objects .requireNonNull (path );
82+ Objects .requireNonNull (version );
83+ }
84+
85+ DefaultCandleInfo (ToolInfo info , boolean fips ) {
86+ this (info .path (), info .version (), fips );
87+ }
6888 }
6989
7090 static WixToolset createToolset () throws ConfigException {
7191 Function <List <ToolLookupResult >, Map <WixTool , ToolInfo >> conv = lookupResults -> {
7292 return lookupResults .stream ().filter (ToolLookupResult ::isValid ).collect (Collectors .
7393 groupingBy (lookupResult -> {
74- return lookupResult .getInfo ().version .toString ();
94+ return lookupResult .info ().version () .toString ();
7595 })).values ().stream ().filter (sameVersionLookupResults -> {
7696 Set <WixTool > sameVersionTools = sameVersionLookupResults .stream ().map (
77- ToolLookupResult ::getTool ).collect (Collectors .toSet ());
97+ ToolLookupResult ::tool ).collect (Collectors .toSet ());
7898 if (sameVersionTools .equals (Set .of (Candle3 )) || sameVersionTools .equals (Set .of (
7999 Light3 ))) {
80100 // There is only one tool from WiX v3 toolset of some version available. Discard it.
81101 return false ;
82102 } else {
83103 return true ;
84104 }
85- }).flatMap (List ::stream ).collect (Collectors .toMap (ToolLookupResult ::getTool ,
86- ToolLookupResult ::getInfo , (ToolInfo x , ToolInfo y ) -> {
105+ }).flatMap (List ::stream ).collect (Collectors .toMap (ToolLookupResult ::tool ,
106+ ToolLookupResult ::info , (ToolInfo x , ToolInfo y ) -> {
87107 return Stream .of (x , y ).sorted (Comparator .comparing ((ToolInfo toolInfo ) -> {
88- return toolInfo .version .toComponentsString ();
108+ return toolInfo .version () .toComponentsString ();
89109 }).reversed ()).findFirst ().get ();
90110 }));
91111 };
@@ -99,8 +119,8 @@ static WixToolset createToolset() throws ConfigException {
99119 };
100120
101121 var toolsInPath = Stream .of (values ()).map (tool -> {
102- return new ToolLookupResult (tool , null );
103- }).toList ();
122+ return ToolLookupResult . lookup (tool , Optional . empty () );
123+ }).filter ( Optional :: isPresent ). map ( Optional :: get ). toList ();
104124
105125 // Try to build a toolset from tools in the PATH first.
106126 var toolset = createToolset .apply (toolsInPath );
@@ -111,9 +131,9 @@ static WixToolset createToolset() throws ConfigException {
111131 // Look up for WiX tools in known locations.
112132 var toolsInKnownWiXDirs = findWixInstallDirs ().stream ().map (dir -> {
113133 return Stream .of (values ()).map (tool -> {
114- return new ToolLookupResult (tool , dir );
134+ return ToolLookupResult . lookup (tool , Optional . of ( dir ) );
115135 });
116- }).flatMap (Function .identity ()).toList ();
136+ }).flatMap (Function .identity ()).filter ( Optional :: isPresent ). map ( Optional :: get ). toList ();
117137
118138 // Build a toolset found in the PATH and in known locations.
119139 var allFoundTools = Stream .of (toolsInPath , toolsInKnownWiXDirs ).flatMap (List ::stream ).filter (
@@ -128,8 +148,8 @@ static WixToolset createToolset() throws ConfigException {
128148 var toolOldVerErr = allFoundTools .stream ().map (lookupResult -> {
129149 if (lookupResult .versionTooOld ) {
130150 return new ConfigException (MessageFormat .format (I18N .getString (
131- "message.wrong-tool-version" ), lookupResult .getInfo ().path ,
132- lookupResult .getInfo ().version , lookupResult .getTool ().minimalVersion ),
151+ "message.wrong-tool-version" ), lookupResult .info ().path () ,
152+ lookupResult .info ().version () , lookupResult .tool ().minimalVersion ),
133153 I18N .getString ("error.no-wix-tools.advice" ));
134154 } else {
135155 return null ;
@@ -144,11 +164,18 @@ static WixToolset createToolset() throws ConfigException {
144164 }
145165 }
146166
147- private static class ToolLookupResult {
167+ private record ToolLookupResult (WixTool tool , ToolInfo info , boolean versionTooOld ) {
168+
169+ ToolLookupResult {
170+ Objects .requireNonNull (tool );
171+ Objects .requireNonNull (info );
172+ }
148173
149- ToolLookupResult (WixTool tool , Path lookupDir ) {
174+ static Optional <ToolLookupResult > lookup (WixTool tool , Optional <Path > lookupDir ) {
175+ Objects .requireNonNull (tool );
176+ Objects .requireNonNull (lookupDir );
150177
151- final Path toolPath = Optional . ofNullable ( lookupDir ) .map (p -> p .resolve (
178+ final Path toolPath = lookupDir .map (p -> p .resolve (
152179 tool .toolFileName )).orElse (tool .toolFileName );
153180
154181 final boolean [] tooOld = new boolean [1 ];
@@ -165,7 +192,19 @@ private static class ToolLookupResult {
165192 final Function <Stream <String >, String > versionParser ;
166193
167194 if (Set .of (Candle3 , Light3 ).contains (tool )) {
168- validator .setCommandLine ("/?" );
195+ final String printVersionArg ;
196+ if (tool == Candle3 ) {
197+ // Add '-fips' to make "candle.exe" print help message and return
198+ // 0 exit code instead of returning error exit code and printing
199+ // "error CNDL0308 : The Federal Information Processing Standard (FIPS) appears to be enabled on the machine..."
200+ // error message if FIPS is enabled.
201+ // If FIPS is disabled, passing '-fips' parameter still makes
202+ // "candle.exe" print help message and return 0 exit code.
203+ printVersionArg = "-fips" ;
204+ } else {
205+ printVersionArg = "-?" ;
206+ }
207+ validator .setCommandLine (printVersionArg );
169208 versionParser = output -> {
170209 String firstLineOfOutput = output .findFirst ().orElse ("" );
171210 int separatorIdx = firstLineOfOutput .lastIndexOf (' ' );
@@ -186,36 +225,35 @@ private static class ToolLookupResult {
186225 return parsedVersion [0 ];
187226 });
188227
189- this .tool = tool ;
190228 if (validator .validate () == null ) {
191229 // Tool found
192- this .versionTooOld = tooOld [0 ];
193- this .info = new ToolInfo (toolPath , parsedVersion [0 ]);
230+ ToolInfo info = new DefaultToolInfo (toolPath , parsedVersion [0 ]);
231+ if (tool == Candle3 ) {
232+ // Detect FIPS mode
233+ var fips = false ;
234+ try {
235+ final var exec = Executor .of (toolPath .toString (), "-?" ).setQuiet (true ).saveOutput (true );
236+ final var exitCode = exec .execute ();
237+ if (exitCode != 0 /* 308 */ ) {
238+ final var output = exec .getOutput ();
239+ if (!output .isEmpty () && output .get (0 ).contains ("error CNDL0308" )) {
240+ fips = true ;
241+ }
242+ }
243+ } catch (IOException ex ) {
244+ Log .verbose (ex );
245+ }
246+ info = new DefaultCandleInfo (info , fips );
247+ }
248+ return Optional .of (new ToolLookupResult (tool , info , tooOld [0 ]));
194249 } else {
195- this .versionTooOld = false ;
196- this .info = null ;
250+ return Optional .empty ();
197251 }
198252 }
199253
200- WixTool getTool () {
201- return tool ;
202- }
203-
204- ToolInfo getInfo () {
205- return info ;
206- }
207-
208254 boolean isValid () {
209- return info != null && !versionTooOld ;
255+ return !versionTooOld ;
210256 }
211-
212- boolean isVersionTooOld () {
213- return versionTooOld ;
214- }
215-
216- private final WixTool tool ;
217- private final ToolInfo info ;
218- private final boolean versionTooOld ;
219257 }
220258
221259 private static Path getSystemDir (String envVar , String knownDir ) {
0 commit comments