Skip to content

Commit 4e7bb6c

Browse files
Fix bad merge
1 parent 47184fc commit 4e7bb6c

File tree

1 file changed

+0
-193
lines changed

1 file changed

+0
-193
lines changed

test/jdk/tools/jpackage/helpers/jdk/jpackage/test/LauncherIconVerifier.java

Lines changed: 0 additions & 193 deletions
Original file line numberDiff line numberDiff line change
@@ -77,199 +77,6 @@ public void applyTo(JPackageCommand cmd) throws IOException {
7777
}
7878
}
7979

80-
private static class WinIconVerifier {
81-
82-
void verifyLauncherIcon(JPackageCommand cmd, String launcherName,
83-
Path expectedIcon, boolean expectedDefault) {
84-
TKit.withTempDirectory("icons", tmpDir -> {
85-
Path launcher = cmd.appLauncherPath(launcherName);
86-
Path iconWorkDir = tmpDir.resolve(launcher.getFileName());
87-
Path iconContainer = iconWorkDir.resolve("container.exe");
88-
Files.createDirectories(iconContainer.getParent());
89-
Files.copy(getDefaultAppLauncher(expectedIcon == null
90-
&& !expectedDefault), iconContainer);
91-
if (expectedIcon != null) {
92-
Executor.tryRunMultipleTimes(() -> {
93-
setIcon(expectedIcon, iconContainer);
94-
}, 3, 5);
95-
}
96-
97-
Path extractedExpectedIcon = extractIconFromExecutable(
98-
iconWorkDir, iconContainer, "expected");
99-
Path extractedActualIcon = extractIconFromExecutable(iconWorkDir,
100-
launcher, "actual");
101-
102-
TKit.trace(String.format(
103-
"Check icon file [%s] of %s launcher is a copy of source icon file [%s]",
104-
extractedActualIcon,
105-
Optional.ofNullable(launcherName).orElse("main"),
106-
extractedExpectedIcon));
107-
108-
if (Files.mismatch(extractedExpectedIcon, extractedActualIcon)
109-
!= -1) {
110-
// On Windows11 .NET API extracting icons from executables
111-
// produce slightly different output for the same icon.
112-
// To workaround it, compare pixels of images and if the
113-
// number of off pixels is below a threshold, assume
114-
// equality.
115-
BufferedImage expectedImg = ImageIO.read(
116-
extractedExpectedIcon.toFile());
117-
BufferedImage actualImg = ImageIO.read(
118-
extractedActualIcon.toFile());
119-
120-
int w = expectedImg.getWidth();
121-
int h = expectedImg.getHeight();
122-
123-
TKit.assertEquals(w, actualImg.getWidth(),
124-
"Check expected and actual icons have the same width");
125-
TKit.assertEquals(h, actualImg.getHeight(),
126-
"Check expected and actual icons have the same height");
127-
128-
int diffPixelCount = 0;
129-
130-
for (int i = 0; i != w; ++i) {
131-
for (int j = 0; j != h; ++j) {
132-
int expectedRGB = expectedImg.getRGB(i, j);
133-
int actualRGB = actualImg.getRGB(i, j);
134-
135-
if (expectedRGB != actualRGB) {
136-
TKit.trace(String.format(
137-
"Images mismatch at [%d, %d] pixel", i,
138-
j));
139-
diffPixelCount++;
140-
}
141-
}
142-
}
143-
144-
double threshold = 0.1;
145-
TKit.assertTrue(((double) diffPixelCount) / (w * h)
146-
< threshold,
147-
String.format(
148-
"Check the number of mismatched pixels [%d] of [%d] is < [%f] threshold",
149-
diffPixelCount, (w * h), threshold));
150-
}
151-
});
152-
}
153-
154-
private WinIconVerifier() {
155-
try {
156-
executableRebranderClass = Class.forName(
157-
"jdk.jpackage.internal.ExecutableRebrander");
158-
159-
lockResource = executableRebranderClass.getDeclaredMethod(
160-
"lockResource", String.class);
161-
// Note: this reflection call requires
162-
// --add-opens jdk.jpackage/jdk.jpackage.internal=ALL-UNNAMED
163-
lockResource.setAccessible(true);
164-
165-
unlockResource = executableRebranderClass.getDeclaredMethod(
166-
"unlockResource", long.class);
167-
unlockResource.setAccessible(true);
168-
169-
iconSwap = executableRebranderClass.getDeclaredMethod(
170-
"iconSwap", long.class, String.class);
171-
iconSwap.setAccessible(true);
172-
} catch (ClassNotFoundException | NoSuchMethodException
173-
| SecurityException ex) {
174-
throw rethrowUnchecked(ex);
175-
}
176-
}
177-
178-
private Path extractIconFromExecutable(Path outputDir, Path executable,
179-
String label) {
180-
// Run .NET code to extract icon from the given executable.
181-
// ExtractAssociatedIcon() will succeed even if the target file
182-
// is locked (by an antivirus). It will output a default icon
183-
// in case of error. To prevent this "fail safe" behavior we try
184-
// lock the target file with Open() call. If the attempt
185-
// fails ExtractAssociatedIcon() is not called and the script exits
186-
// with the exit code that will be trapped
187-
// inside of Executor.executeAndRepeatUntilExitCode() method that
188-
// will keep running the script until it succeeds or the number of
189-
// allowed attempts is exceeded.
190-
191-
Path extractedIcon = outputDir.resolve(label + ".bmp");
192-
String script = String.join(";",
193-
String.format(
194-
"try { [System.io.File]::Open('%s', 'Open', 'Read', 'None') } catch { exit 100 }",
195-
executable.toAbsolutePath().normalize()),
196-
"[System.Reflection.Assembly]::LoadWithPartialName('System.Drawing')",
197-
String.format(
198-
"[System.Drawing.Icon]::ExtractAssociatedIcon('%s').ToBitmap().Save('%s', [System.Drawing.Imaging.ImageFormat]::Bmp)",
199-
executable.toAbsolutePath().normalize(),
200-
extractedIcon.toAbsolutePath().normalize()));
201-
202-
Executor.of("powershell", "-NoLogo", "-NoProfile", "-Command",
203-
script).executeAndRepeatUntilExitCode(0, 5, 10);
204-
205-
return extractedIcon;
206-
}
207-
208-
private Path getDefaultAppLauncher(boolean noIcon) {
209-
// Create app image with the sole purpose to get the default app launcher
210-
Path defaultAppOutputDir = TKit.workDir().resolve(String.format(
211-
"out-%d", ProcessHandle.current().pid()));
212-
JPackageCommand cmd = JPackageCommand.helloAppImage().setFakeRuntime().setArgumentValue(
213-
"--dest", defaultAppOutputDir);
214-
215-
String launcherName;
216-
if (noIcon) {
217-
launcherName = "no-icon";
218-
new AdditionalLauncher(launcherName).setNoIcon().applyTo(cmd);
219-
} else {
220-
launcherName = null;
221-
}
222-
223-
if (!Files.isExecutable(cmd.appLauncherPath(launcherName))) {
224-
cmd.execute();
225-
}
226-
return cmd.appLauncherPath(launcherName);
227-
}
228-
229-
private void setIcon(Path iconPath, Path launcherPath) {
230-
TKit.trace(String.format("Set icon of [%s] launcher to [%s] file",
231-
launcherPath, iconPath));
232-
try {
233-
launcherPath.toFile().setWritable(true, true);
234-
try {
235-
long lock = 0;
236-
try {
237-
lock = (Long) lockResource.invoke(null, new Object[]{
238-
launcherPath.toAbsolutePath().normalize().toString()});
239-
if (lock == 0) {
240-
throw new RuntimeException(String.format(
241-
"Failed to lock [%s] executable",
242-
launcherPath));
243-
}
244-
var exitCode = (Integer) iconSwap.invoke(null, new Object[]{
245-
lock,
246-
iconPath.toAbsolutePath().normalize().toString()});
247-
if (exitCode != 0) {
248-
throw new RuntimeException(String.format(
249-
"Failed to swap icon of [%s] executable",
250-
launcherPath));
251-
}
252-
} finally {
253-
if (lock != 0) {
254-
unlockResource.invoke(null, new Object[]{lock});
255-
}
256-
}
257-
} catch (IllegalAccessException | InvocationTargetException ex) {
258-
throw rethrowUnchecked(ex);
259-
}
260-
} finally {
261-
launcherPath.toFile().setWritable(false, true);
262-
}
263-
}
264-
265-
static final WinIconVerifier instance = new WinIconVerifier();
266-
267-
private final Class<?> executableRebranderClass;
268-
private final Method lockResource;
269-
private final Method unlockResource;
270-
private final Method iconSwap;
271-
}
272-
27380
private String launcherName;
27481
private Path expectedIcon;
27582
private boolean expectedDefault;

0 commit comments

Comments
 (0)