--- old/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java 2019-08-28 08:54:14.766426100 -0400 +++ new/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxAppBundler.java 2019-08-28 08:54:12.628184900 -0400 @@ -126,7 +126,8 @@ } private File doAppBundle(Map params, - File outputDirectory, boolean dependentTask) throws PackagerException { + File outputDirectory, boolean dependentTask) + throws PackagerException { try { File rootDirectory = createRoot(params, outputDirectory, dependentTask, APP_NAME.fetchFrom(params)); --- old/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java 2019-08-28 08:54:59.984898900 -0400 +++ new/src/jdk.jpackage/linux/classes/jdk/jpackage/internal/LinuxRpmBundler.java 2019-08-28 08:54:57.753055900 -0400 @@ -124,8 +124,8 @@ params -> I18N.getString("param.license-type.default"), (s, p) -> s ); - - public static final BundlerParamInfo GROUP = + + public static final BundlerParamInfo GROUP = new StandardBundlerParam<>( Arguments.CLIOptions.LINUX_CATEGORY.getId(), String.class, --- old/src/jdk.jpackage/linux/native/libapplauncher/LinuxPlatform.cpp 2019-08-28 08:55:19.711678900 -0400 +++ new/src/jdk.jpackage/linux/native/libapplauncher/LinuxPlatform.cpp 2019-08-28 08:55:16.810023100 -0400 @@ -81,7 +81,8 @@ } TString LinuxPlatform::GetPackageRuntimeBinDirectory() { - return FilePath::IncludeTrailingSeparator(GetPackageRootDirectory()) + _T("runtime/bin"); + return FilePath::IncludeTrailingSeparator(GetPackageRootDirectory()) + + _T("runtime/bin"); } void LinuxPlatform::ShowMessage(TString title, TString description) { @@ -1017,8 +1018,8 @@ return FindXMLChild(root->_next, name); } -/* Search for an attribute with the given name and returns the contents. Returns NULL if - * attribute is not found +/* Search for an attribute with the given name and returns the contents. + * Returns NULL if attribute is not found */ TCHAR* FindXMLAttribute(XMLAttribute* attr, const TCHAR* name) { if (attr == NULL) return NULL; --- old/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppStoreBundler.java 2019-08-28 08:55:39.801266200 -0400 +++ new/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacAppStoreBundler.java 2019-08-28 08:55:37.661024800 -0400 @@ -57,24 +57,24 @@ "mac.signing-key-app", String.class, params -> { - String result = MacBaseInstallerBundler.findKey( - "3rd Party Mac Developer Application: " + - SIGNING_KEY_USER.fetchFrom(params), - SIGNING_KEYCHAIN.fetchFrom(params), + String result = MacBaseInstallerBundler.findKey( + "3rd Party Mac Developer Application: " + + SIGNING_KEY_USER.fetchFrom(params), + SIGNING_KEYCHAIN.fetchFrom(params), + VERBOSE.fetchFrom(params)); + if (result != null) { + MacCertificate certificate = new MacCertificate(result, VERBOSE.fetchFrom(params)); - if (result != null) { - MacCertificate certificate = new MacCertificate(result, - VERBOSE.fetchFrom(params)); - - if (!certificate.isValid()) { - Log.error(MessageFormat.format( - I18N.getString("error.certificate.expired"), - result)); - } + + if (!certificate.isValid()) { + Log.error(MessageFormat.format( + I18N.getString("error.certificate.expired"), + result)); } + } - return result; - }, + return result; + }, (s, p) -> s); public static final BundlerParamInfo MAC_APP_STORE_PKG_SIGNING_KEY = @@ -82,25 +82,25 @@ "mac.signing-key-pkg", String.class, params -> { - String result = MacBaseInstallerBundler.findKey( - "3rd Party Mac Developer Installer: " + - SIGNING_KEY_USER.fetchFrom(params), - SIGNING_KEYCHAIN.fetchFrom(params), - VERBOSE.fetchFrom(params)); - - if (result != null) { - MacCertificate certificate = new MacCertificate( - result, VERBOSE.fetchFrom(params)); - - if (!certificate.isValid()) { - Log.error(MessageFormat.format( - I18N.getString("error.certificate.expired"), - result)); - } + String result = MacBaseInstallerBundler.findKey( + "3rd Party Mac Developer Installer: " + + SIGNING_KEY_USER.fetchFrom(params), + SIGNING_KEYCHAIN.fetchFrom(params), + VERBOSE.fetchFrom(params)); + + if (result != null) { + MacCertificate certificate = new MacCertificate( + result, VERBOSE.fetchFrom(params)); + + if (!certificate.isValid()) { + Log.error(MessageFormat.format( + I18N.getString("error.certificate.expired"), + result)); } + } - return result; - }, + return result; + }, (s, p) -> s); public static final StandardBundlerParam MAC_APP_STORE_ENTITLEMENTS = --- old/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java 2019-08-28 08:55:57.774015700 -0400 +++ new/src/jdk.jpackage/macosx/classes/jdk/jpackage/internal/MacDmgBundler.java 2019-08-28 08:55:54.403350800 -0400 @@ -134,7 +134,8 @@ } File licFile = new File(licFileStr); - byte[] licenseContentOriginal = Files.readAllBytes(licFile.toPath()); + byte[] licenseContentOriginal = + Files.readAllBytes(licFile.toPath()); String licenseInBase64 = Base64.getEncoder().encodeToString(licenseContentOriginal); --- old/src/jdk.jpackage/macosx/native/libapplauncher/MacPlatform.mm 2019-08-28 08:57:11.417636500 -0400 +++ new/src/jdk.jpackage/macosx/native/libapplauncher/MacPlatform.mm 2019-08-28 08:57:08.402778200 -0400 @@ -464,7 +464,8 @@ _T("app.version"))); keys.insert(std::map::value_type(CONFIG_MAINJAR_KEY, _T("JavaMainJarName"))); - keys.insert(std::map::value_type(CONFIG_MAINMODULE_KEY, + keys.insert(std::map::value_type(CONFIG_MAINMODULE_KEY, _T("JavaMainModuleName"))); keys.insert(std::map::value_type( CONFIG_MAINCLASSNAME_KEY, _T("JavaMainClassName"))); @@ -474,7 +475,8 @@ _T("CFBundleName"))); keys.insert(std::map::value_type(JAVA_RUNTIME_KEY, _T("JavaRuntime"))); - keys.insert(std::map::value_type(JPACKAGE_APP_DATA_DIR, + keys.insert(std::map::value_type(JPACKAGE_APP_DATA_DIR, _T("CFBundleIdentifier"))); keys.insert(std::map::value_type(CONFIG_SPLASH_KEY, --- old/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java 2019-08-28 08:57:36.770525500 -0400 +++ new/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AbstractAppImageBuilder.java 2019-08-28 08:57:33.349059300 -0400 @@ -46,7 +46,7 @@ /* * AbstractAppImageBuilder * This is sub-classed by each of the platform dependent AppImageBuilder - * classes, and contains resource processing code common to all platforms. + * classes, and contains resource processing code common to all platforms. */ public abstract class AbstractAppImageBuilder { --- old/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AddLauncherArguments.java 2019-08-28 08:57:51.562610200 -0400 +++ new/src/jdk.jpackage/share/classes/jdk/jpackage/internal/AddLauncherArguments.java 2019-08-28 08:57:49.533571100 -0400 @@ -108,7 +108,7 @@ putUnlessNull(bundleParams, CLIOptions.LINUX_CATEGORY.getId(), getOptionValue(CLIOptions.LINUX_CATEGORY)); - + putUnlessNull(bundleParams, CLIOptions.LINUX_DEB_COPYRIGHT_FILE.getId(), getOptionValue(CLIOptions.LINUX_DEB_COPYRIGHT_FILE)); --- old/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java 2019-08-28 08:58:06.584100200 -0400 +++ new/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Arguments.java 2019-08-28 08:58:04.524860600 -0400 @@ -322,7 +322,7 @@ LINUX_DEB_MAINTAINER ("linux-deb-maintainer", OptionCategories.PLATFORM_LINUX), - + LINUX_DEB_COPYRIGHT_FILE ("linux-deb-copyright-file", OptionCategories.PLATFORM_LINUX), --- old/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Log.java 2019-08-28 08:58:21.362584800 -0400 +++ new/src/jdk.jpackage/share/classes/jdk/jpackage/internal/Log.java 2019-08-28 08:58:19.161942400 -0400 @@ -44,7 +44,7 @@ // verbose defaults to true unless environment variable JPACKAGE_DEBUG // is set to true. // Then it is only set to true by using --verbose jpackage option - + public Logger() { verbose = ("true".equals(System.getenv("JPACKAGE_DEBUG"))); } --- old/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ValidOptions.java 2019-08-28 08:58:36.284472400 -0400 +++ new/src/jdk.jpackage/share/classes/jdk/jpackage/internal/ValidOptions.java 2019-08-28 08:58:33.819625000 -0400 @@ -102,7 +102,7 @@ options.put(CLIOptions.WIN_DIR_CHOOSER.getId(), USE.INSTALL); options.put(CLIOptions.WIN_UPGRADE_UUID.getId(), USE.INSTALL); options.put(CLIOptions.WIN_PER_USER_INSTALLATION.getId(), - USE.INSTALL); + USE.INSTALL); } if (Platform.getPlatform() == Platform.MAC) { @@ -110,22 +110,23 @@ options.put(CLIOptions.MAC_BUNDLE_NAME.getId(), USE.ALL); options.put(CLIOptions.MAC_BUNDLE_IDENTIFIER.getId(), USE.ALL); options.put(CLIOptions.MAC_BUNDLE_SIGNING_PREFIX.getId(), - USE.ALL); + USE.ALL); options.put(CLIOptions.MAC_SIGNING_KEY_NAME.getId(), USE.ALL); options.put(CLIOptions.MAC_SIGNING_KEYCHAIN.getId(), USE.ALL); options.put(CLIOptions.MAC_APP_STORE_CATEGORY.getId(), USE.ALL); options.put(CLIOptions.MAC_APP_STORE_ENTITLEMENTS.getId(), - USE.ALL); + USE.ALL); } if (Platform.getPlatform() == Platform.LINUX) { options.put(CLIOptions.LINUX_BUNDLE_NAME.getId(), USE.INSTALL); options.put(CLIOptions.LINUX_DEB_MAINTAINER.getId(), USE.INSTALL); - options.put(CLIOptions.LINUX_DEB_COPYRIGHT_FILE.getId(), USE.INSTALL); + options.put(CLIOptions.LINUX_DEB_COPYRIGHT_FILE.getId(), + USE.INSTALL); options.put(CLIOptions.LINUX_CATEGORY.getId(), USE.INSTALL); options.put(CLIOptions.LINUX_RPM_LICENSE_TYPE.getId(), USE.INSTALL); options.put(CLIOptions.LINUX_PACKAGE_DEPENDENCIES.getId(), - USE.INSTALL); + USE.INSTALL); options.put(CLIOptions.LINUX_MENU_GROUP.getId(), USE.INSTALL); options.put(CLIOptions.RELEASE.getId(), USE.INSTALL); } --- old/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties 2019-08-28 08:58:51.742172000 -0400 +++ new/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources.properties 2019-08-28 08:58:49.542529700 -0400 @@ -217,7 +217,7 @@ MSG_Help_mac_launcher=\ \ --mac-bundle-identifier \n\ -\ An identifier that uniquely identifies the application for MacOSX\n\ +\ An identifier that uniquely identifies the application for macOS\n\ \ Defaults to the value of --identifier option.\n\ \ May only use alphanumeric (A-Z,a-z,0-9), hyphen (-),\n\ \ and period (.) characters.\n\ --- old/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_ja.properties 2019-08-28 09:00:08.796060400 -0400 +++ new/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_ja.properties 2019-08-28 08:59:46.031821100 -0400 @@ -217,7 +217,7 @@ MSG_Help_mac_launcher=\ \ --mac-bundle-identifier \n\ -\ An identifier that uniquely identifies the application for MacOSX\n\ +\ An identifier that uniquely identifies the application for macOS\n\ \ Defaults to the value of --identifier option.\n\ \ May only use alphanumeric (A-Z,a-z,0-9), hyphen (-),\n\ \ and period (.) characters.\n\ --- old/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_zh_CN.properties 2019-08-28 09:00:38.660436400 -0400 +++ new/src/jdk.jpackage/share/classes/jdk/jpackage/internal/resources/HelpResources_zh_CN.properties 2019-08-28 09:00:36.097986800 -0400 @@ -217,7 +217,7 @@ MSG_Help_mac_launcher=\ \ --mac-bundle-identifier \n\ -\ An identifier that uniquely identifies the application for MacOSX\n\ +\ An identifier that uniquely identifies the application for macOS\n\ \ Defaults to the value of --identifier option.\n\ \ May only use alphanumeric (A-Z,a-z,0-9), hyphen (-),\n\ \ and period (.) characters.\n\ --- old/src/jdk.jpackage/share/classes/jdk/jpackage/main/CommandLine.java 2019-08-28 09:01:13.354904800 -0400 +++ new/src/jdk.jpackage/share/classes/jdk/jpackage/main/CommandLine.java 2019-08-28 09:01:09.953039300 -0400 @@ -71,7 +71,8 @@ return newArgs.toArray(new String[newArgs.size()]); } - private static void appendParsedCommandArgs(List newArgs, List args) throws IOException { + private static void appendParsedCommandArgs(List newArgs, + List args) throws IOException { for (String arg : args) { if (arg.length() > 1 && arg.charAt(0) == '@') { arg = arg.substring(1); @@ -86,11 +87,13 @@ } } - private static void loadCmdFile(String name, List args) throws IOException { + private static void loadCmdFile(String name, List args) + throws IOException { if (!Files.isReadable(Path.of(name))) { throw new FileNotFoundException(name); } - try (Reader r = Files.newBufferedReader(Paths.get(name), Charset.defaultCharset())) { + try (Reader r = Files.newBufferedReader(Paths.get(name), + Charset.defaultCharset())) { Tokenizer t = new Tokenizer(r); String s; while ((s = t.nextToken()) != null) { @@ -149,7 +152,9 @@ switch (ch) { case '\n': case '\r': - while (ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t' || ch == '\f') { + while (ch == ' ' || ch == '\n' + || ch == '\r' || ch == '\t' + || ch == '\f') { ch = in.read(); } continue; --- old/src/jdk.jpackage/share/classes/module-info.java 2019-08-28 09:01:29.434214900 -0400 +++ new/src/jdk.jpackage/share/classes/module-info.java 2019-08-28 09:01:27.356374700 -0400 @@ -43,7 +43,7 @@ *

* * @moduleGraph - * @since 13 + * @since 14 */ module jdk.jpackage { --- old/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java 2019-08-28 09:02:08.454966900 -0400 +++ new/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java 2019-08-28 09:02:05.834116500 -0400 @@ -128,7 +128,8 @@ // Embed msi in msi wrapper exe. embedMSI(exePath, msi.getAbsolutePath()); - Path dstExePath = Paths.get(outdir.getAbsolutePath(), Path.of(exePath).getFileName().toString()); + Path dstExePath = Paths.get(outdir.getAbsolutePath(), + Path.of(exePath).getFileName().toString()); Files.deleteIfExists(dstExePath); Files.copy(Path.of(exePath), dstExePath); --- old/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java 2019-08-28 09:02:31.952420300 -0400 +++ new/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinMsiBundler.java 2019-08-28 09:02:29.110165400 -0400 @@ -421,7 +421,8 @@ String licenseFile = LICENSE_FILE.fetchFrom(params); if (licenseFile != null) { - // need to copy license file to the working directory and convert to rtf if needed + // need to copy license file to the working directory + // and convert to rtf if needed File lfile = new File(licenseFile); File destFile = new File(CONFIG_ROOT.fetchFrom(params), lfile.getName()); @@ -554,7 +555,8 @@ File launcher = new File(imageRootDir, WinAppBundler.getLauncherRelativePath(params)); if (launcher.exists()) { - String iconPath = launcher.getAbsolutePath().replace(".exe", ".ico"); + String iconPath = launcher.getAbsolutePath().replace( + ".exe", ".ico"); if (MENU_HINT.fetchFrom(params)) { xml.writeStartElement("Icon"); xml.writeAttribute("Id", "StartMenuIcon.exe"); @@ -628,7 +630,8 @@ data.put("JpAppVendor", VENDOR.fetchFrom(params)); data.put("JpAppVersion", PRODUCT_VERSION.fetchFrom(params)); - data.put("JpConfigDir", CONFIG_ROOT.fetchFrom(params).getAbsolutePath()); + data.put("JpConfigDir", + CONFIG_ROOT.fetchFrom(params).getAbsolutePath()); File imageRootDir = WIN_APP_IMAGE.fetchFrom(params); @@ -649,7 +652,8 @@ String fname = "wixhelper.dll"; try (InputStream is = getResourceAsStream(fname)) { Files.copy(is, Paths.get( - CONFIG_ROOT.fetchFrom(params).getAbsolutePath(), fname)); + CONFIG_ROOT.fetchFrom(params).getAbsolutePath(), + fname)); } } @@ -658,7 +662,8 @@ String fname = "MsiInstallerStrings_" + loc + ".wxl"; try (InputStream is = getResourceAsStream(fname)) { Files.copy(is, Paths.get( - CONFIG_ROOT.fetchFrom(params).getAbsolutePath(), fname)); + CONFIG_ROOT.fetchFrom(params).getAbsolutePath(), + fname)); } } --- old/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsAppImageBuilder.java 2019-08-28 09:03:14.683444700 -0400 +++ new/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsAppImageBuilder.java 2019-08-28 09:02:50.905185900 -0400 @@ -388,6 +388,7 @@ private static native int iconSwap(String iconTarget, String launcher); - private static native int versionSwap(String executableProperties, String launcher); + private static native int versionSwap(String executableProperties, + String launcher); } --- old/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsRegistry.java 2019-08-28 09:03:47.365474400 -0400 +++ new/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WindowsRegistry.java 2019-08-28 09:03:44.896626600 -0400 @@ -124,7 +124,8 @@ private static native void closeRegistryKey(long lKey); /** - * Compares two Windows paths regardless case and if paths are short or long. + * Compares two Windows paths regardless case and if paths + * are short or long. * * @param path1 path to compare * @param path2 path to compare --- old/src/jdk.jpackage/windows/native/libapplauncher/FilePath.cpp 2019-08-28 09:04:05.468823100 -0400 +++ new/src/jdk.jpackage/windows/native/libapplauncher/FilePath.cpp 2019-08-28 09:04:02.286361900 -0400 @@ -113,7 +113,8 @@ if (lDirectoryName.GetData() == NULL) { return false; } - memcpy(lDirectoryName.GetData(), directoryName.data(), (directoryName.size() + 2) * sizeof(TCHAR)); + memcpy(lDirectoryName.GetData(), directoryName.data(), + (directoryName.size() + 2) * sizeof(TCHAR)); lDirectoryName[directoryName.size() + 1] = NULL; // Double null terminate for SHFileOperation. --- old/src/jdk.jpackage/windows/native/libapplauncher/WindowsPlatform.cpp 2019-08-28 09:04:33.547764200 -0400 +++ new/src/jdk.jpackage/windows/native/libapplauncher/WindowsPlatform.cpp 2019-08-28 09:04:30.724109900 -0400 @@ -705,7 +705,8 @@ } if (::CreateProcess(Application.data(), (wchar_t*)command.data(), NULL, - NULL, FALSE, 0, NULL, NULL, &startupInfo, &FProcessInfo) == FALSE) { + NULL, FALSE, 0, NULL, NULL, &startupInfo, &FProcessInfo) + == FALSE) { TString message = PlatformString::Format( _T("Error: Unable to create process %s"), Application.data()); --- old/src/jdk.jpackage/windows/native/libjpackage/FileUtils.cpp 2019-08-28 09:05:09.942665300 -0400 +++ new/src/jdk.jpackage/windows/native/libjpackage/FileUtils.cpp 2019-08-28 09:04:58.377842500 -0400 @@ -1,702 +1,709 @@ -/* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include -#include -#include - -#include "FileUtils.h" -#include "WinErrorHandling.h" -#include "Log.h" - - -// Needed by FileUtils::isDirectoryNotEmpty -#pragma comment(lib, "shlwapi") - - -namespace FileUtils { - -namespace { - - -tstring reservedFilenameChars() { - tstring buf; - for (char charCode = 0; charCode < 32; ++charCode) { - buf.append(1, charCode); - } - buf += _T("<>:\"|?*/\\"); - return buf; -} - -} // namespace - -bool isDirSeparator(const tstring::value_type c) { - return (c == '/' || c == '\\'); -} - -bool isFileExists(const tstring &filePath) { - return GetFileAttributes(filePath.c_str()) != INVALID_FILE_ATTRIBUTES; -} - -namespace { -bool isDirectoryAttrs(const DWORD attrs) { - return attrs != INVALID_FILE_ATTRIBUTES && (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0; -} -} // namespace - -bool isDirectory(const tstring &filePath) { - return isDirectoryAttrs(GetFileAttributes(filePath.c_str())); -} - -bool isDirectoryNotEmpty(const tstring &dirPath) { - if (!isDirectory(dirPath)) { - return false; - } - return FALSE == PathIsDirectoryEmpty(dirPath.c_str()); -} - -tstring dirname(const tstring &path) -{ - tstring::size_type pos = path.find_last_of(_T("\\/")); - if (pos != tstring::npos) { - pos = path.find_last_not_of(_T("\\/"), pos); // skip trailing slashes - } - return pos == tstring::npos ? tstring() : path.substr(0, pos + 1); -} - -tstring basename(const tstring &path) { - const tstring::size_type pos = path.find_last_of(_T("\\/")); - if (pos == tstring::npos) { - return path; - } - return path.substr(pos + 1); -} - -tstring suffix(const tstring &path) { - const tstring::size_type pos = path.rfind('.'); - if (pos == tstring::npos) { - return tstring(); - } - const tstring::size_type dirSepPos = path.find_first_of(_T("\\/"), - pos + 1); - if (dirSepPos != tstring::npos) { - return tstring(); - } - // test for '/..' and '..' cases - if (pos != 0 && path[pos - 1] == '.' - && (pos == 1 || isDirSeparator(path[pos - 2]))) { - return tstring(); - } - return path.substr(pos); -} - -tstring combinePath(const tstring& parent, const tstring& child) { - if (parent.empty()) { - return child; - } - if (child.empty()) { - return parent; - } - - tstring parentWOSlash = removeTrailingSlash(parent); - // also handle the case when child contains starting slash - bool childHasSlash = isDirSeparator(child.front()); - tstring childWOSlash = childHasSlash ? child.substr(1) : child; - - return parentWOSlash + _T("\\") + childWOSlash; -} - -tstring removeTrailingSlash(const tstring& path) { - if (path.empty()) { - return path; - } - tstring::const_reverse_iterator it = path.rbegin(); - tstring::const_reverse_iterator end = path.rend(); - - while (it != end && isDirSeparator(*it)) { - ++it; - } - return path.substr(0, end - it); -} - -tstring normalizePath(tstring v) { - std::replace(v.begin(), v.end(), '/', '\\'); - return tstrings::toLower(v); -} - -namespace { - -bool createNewFile(const tstring& path) { - HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); - // if the file exists => h == INVALID_HANDLE_VALUE & GetLastError returns ERROR_FILE_EXISTS - if (h != INVALID_HANDLE_VALUE) { - CloseHandle(h); - LOG_TRACE(tstrings::any() << "Created [" << path << "] file"); - return true; - } - return false; -} - -} // namespace - -tstring createTempFile(const tstring &prefix, const tstring &suffix, const tstring &path) -{ - const tstring invalidChars = reservedFilenameChars(); - - if (prefix.find_first_of(invalidChars) != tstring::npos) { - JP_THROW(tstrings::any() << "Illegal characters in prefix=" << prefix); - } - - if (suffix.find_first_of(invalidChars) != tstring::npos) { - JP_THROW(tstrings::any() << "Illegal characters in suffix=" << suffix); - } - - int rnd = (int)GetTickCount(); - - // do no more than 100 attempts - for (int i=0; i<100; i++) { - const tstring filePath = mkpath() << path << (prefix + (tstrings::any() << (rnd + i)).tstr() + suffix); - if (createNewFile(filePath)) { - return filePath; - } - } - - // 100 attempts failed - JP_THROW(tstrings::any() << "createTempFile(" << prefix << ", " - << suffix << ", " - << path << ") failed"); -} - -tstring createTempDirectory(const tstring &prefix, const tstring &suffix, const tstring &basedir) { - const tstring filePath = createTempFile(prefix, suffix, basedir); - // delete the file and create directory with the same name - deleteFile(filePath); - createDirectory(filePath); - return filePath; -} - -tstring createUniqueFile(const tstring &prototype) { - if (createNewFile(prototype)) { - return prototype; - } - - return createTempFile(replaceSuffix(basename(prototype)), - suffix(prototype), dirname(prototype)); -} - -namespace { - -void createDir(const tstring path, LPSECURITY_ATTRIBUTES saAttr, tstring_array* createdDirs=0) { - if (CreateDirectory(path.c_str(), saAttr)) { - LOG_TRACE(tstrings::any() << "Created [" << path << "] directory"); - if (createdDirs) { - createdDirs->push_back(removeTrailingSlash(path)); - } - } else { - const DWORD createDirectoryErr = GetLastError(); - // if saAttr is specified, fail even if the directory exists - if (saAttr != NULL || !isDirectory(path)) { - JP_THROW(SysError(tstrings::any() << "CreateDirectory(" << path << ") failed", - CreateDirectory, createDirectoryErr)); - } - } -} - -} - -void createDirectory(const tstring &path, tstring_array* createdDirs) { - const tstring dirPath = removeTrailingSlash(path) + _T("\\"); - - tstring::size_type pos = dirPath.find_first_of(_T("\\/")); - while (pos != tstring::npos) { - const tstring subdirPath = dirPath.substr(0, pos + 1); - createDir(subdirPath, NULL, createdDirs); - pos = dirPath.find_first_of(_T("\\/"), pos + 1); - } -} - - -void copyFile(const tstring& fromPath, const tstring& toPath, bool failIfExists) { - createDirectory(dirname(toPath)); - if (!CopyFile(fromPath.c_str(), toPath.c_str(), (failIfExists ? TRUE : FALSE))) { - JP_THROW(SysError(tstrings::any() - << "CopyFile(" << fromPath << ", " << toPath << ", " - << failIfExists << ") failed", CopyFile)); - } - LOG_TRACE(tstrings::any() << "Copied [" << fromPath << "] file to [" - << toPath << "]"); -} - - -namespace { - -void moveFileImpl(const tstring& fromPath, const tstring& toPath, - DWORD flags) { - const bool isDir = isDirectory(fromPath); - if (!MoveFileEx(fromPath.c_str(), toPath.empty() ? NULL : toPath.c_str(), - flags)) { - JP_THROW(SysError(tstrings::any() << "MoveFileEx(" << fromPath - << ", " << toPath << ", " << flags << ") failed", - MoveFileEx)); - } - - const bool onReboot = 0 != (flags & MOVEFILE_DELAY_UNTIL_REBOOT); - - const LPCTSTR label = isDir ? _T("folder") : _T("file"); - - tstrings::any msg; - if (!toPath.empty()) { - if (onReboot) { - msg << "Move"; - } else { - msg << "Moved"; - } - msg << " '" << fromPath << "' " << label << " to '" << toPath << "'"; - } else { - if (onReboot) { - msg << "Delete"; - } else { - msg << "Deleted"; - } - msg << " '" << fromPath << "' " << label; - } - if (onReboot) { - msg << " on reboot"; - } - LOG_TRACE(msg); -} - -} // namespace - - -void moveFile(const tstring& fromPath, const tstring& toPath, bool failIfExists) -{ - createDirectory(dirname(toPath)); - - DWORD flags = MOVEFILE_COPY_ALLOWED; - if (!failIfExists) { - flags |= MOVEFILE_REPLACE_EXISTING; - } - - moveFileImpl(fromPath, toPath, flags); -} - -void deleteFile(const tstring &path) -{ - if (!deleteFile(path, std::nothrow)) { - JP_THROW(SysError(tstrings::any() - << "DeleteFile(" << path << ") failed", DeleteFile)); - } -} - -namespace { - -bool notFound(const DWORD status=GetLastError()) { - return status == ERROR_FILE_NOT_FOUND || status == ERROR_PATH_NOT_FOUND; -} - -bool deleteFileImpl(const std::nothrow_t &, const tstring &path) { - const bool deleted = (DeleteFile(path.c_str()) != 0); - if (deleted) { - LOG_TRACE(tstrings::any() << "Deleted [" << path << "] file"); - return true; - } - return notFound(); -} - -} // namespace - -bool deleteFile(const tstring &path, const std::nothrow_t &) throw() -{ - bool deleted = deleteFileImpl(std::nothrow, path); - const DWORD status = GetLastError(); - if (!deleted && status == ERROR_ACCESS_DENIED) { - DWORD attrs = GetFileAttributes(path.c_str()); - SetLastError(status); - if (attrs == INVALID_FILE_ATTRIBUTES) { - return false; - } - if (attrs & FILE_ATTRIBUTE_READONLY) { - // DeleteFile() failed because file is R/O. - // Remove R/O attribute and retry DeleteFile(). - attrs &= ~FILE_ATTRIBUTE_READONLY; - if (SetFileAttributes(path.c_str(), attrs)) { - LOG_TRACE(tstrings::any() << "Discarded R/O attribute from [" - << path << "] file"); - deleted = deleteFileImpl(std::nothrow, path); - } else { - LOG_WARNING(SysError(tstrings::any() - << "Failed to discard R/O attribute from [" - << path << "] file. File will not be deleted", - SetFileAttributes).what()); - SetLastError(status); - } - } - } - - return deleted || notFound(); -} - -void deleteDirectory(const tstring &path) -{ - if (!deleteDirectory(path, std::nothrow)) { - JP_THROW(SysError(tstrings::any() - << "RemoveDirectory(" << path << ") failed", RemoveDirectory)); - } -} - -bool deleteDirectory(const tstring &path, const std::nothrow_t &) throw() -{ - const bool deleted = (RemoveDirectory(path.c_str()) != 0); - if (deleted) { - LOG_TRACE(tstrings::any() << "Deleted [" << path << "] directory"); - } - return deleted || notFound(); -} - -namespace { - -class DeleteFilesCallback: public DirectoryCallback { -public: - explicit DeleteFilesCallback(bool ff): failfast(ff), failed(false) { - } - - virtual bool onFile(const tstring& path) { - if (failfast) { - deleteFile(path); - } else { - updateStatus(deleteFile(path, std::nothrow)); - } - return true; - } - - bool good() const { - return !failed; - } - -protected: - void updateStatus(bool success) { - if (!success) { - failed = true; - } - } - - const bool failfast; -private: - bool failed; -}; - -class DeleteAllCallback: public DeleteFilesCallback { -public: - explicit DeleteAllCallback(bool failfast): DeleteFilesCallback(failfast) { - } - - virtual bool onDirectory(const tstring& path) { - if (failfast) { - deleteDirectoryRecursive(path); - } else { - updateStatus(deleteDirectoryRecursive(path, std::nothrow)); - } - return true; - } -}; - - -class BatchDeleter { - const tstring dirPath; - bool recursive; -public: - explicit BatchDeleter(const tstring& path): dirPath(path) { - deleteSubdirs(false); - } - - BatchDeleter& deleteSubdirs(bool v) { - recursive = v; - return *this; - } - - void execute() const { - if (!isFileExists(dirPath)) { - return; - } - iterateDirectory(true /* fail fast */); - if (recursive) { - deleteDirectory(dirPath); - } - } - - bool execute(const std::nothrow_t&) const { - if (!isFileExists(dirPath)) { - return true; - } - - if (!isDirectory(dirPath)) { - return false; - } - - JP_TRY; - if (!iterateDirectory(false /* ignore errors */)) { - return false; - } - if (recursive) { - return deleteDirectory(dirPath, std::nothrow); - } - return true; - JP_CATCH_ALL; - - return false; - } - -private: - bool iterateDirectory(bool failfast) const { - std::unique_ptr callback; - if (recursive) { - callback = std::unique_ptr( - new DeleteAllCallback(failfast)); - } else { - callback = std::unique_ptr( - new DeleteFilesCallback(failfast)); - } - - FileUtils::iterateDirectory(dirPath, *callback); - return callback->good(); - } -}; - -} // namespace - -void deleteFilesInDirectory(const tstring &dirPath) { - BatchDeleter(dirPath).execute(); -} - -bool deleteFilesInDirectory(const tstring &dirPath, - const std::nothrow_t &) throw() { - return BatchDeleter(dirPath).execute(std::nothrow); -} - -void deleteDirectoryRecursive(const tstring &dirPath) { - BatchDeleter(dirPath).deleteSubdirs(true).execute(); -} - -bool deleteDirectoryRecursive(const tstring &dirPath, - const std::nothrow_t &) throw() { - return BatchDeleter(dirPath).deleteSubdirs(true).execute(std::nothrow); -} - -namespace { - -struct FindFileDeleter { - typedef HANDLE pointer; - - void operator()(HANDLE h) { - if (h && h != INVALID_HANDLE_VALUE) { - FindClose(h); - } - } -}; - -typedef std::unique_ptr UniqueFindFileHandle; - -}; // namesace -void iterateDirectory(const tstring &dirPath, DirectoryCallback& callback) -{ - const tstring searchString = combinePath(dirPath, _T("*")); - WIN32_FIND_DATA findData; - UniqueFindFileHandle h(FindFirstFile(searchString.c_str(), &findData)); - if (h.get() == INVALID_HANDLE_VALUE) { - // GetLastError() == ERROR_FILE_NOT_FOUND is OK - no files in the directory - // ERROR_PATH_NOT_FOUND is returned if the parent directory does not exist - if (GetLastError() != ERROR_FILE_NOT_FOUND) { - JP_THROW(SysError(tstrings::any() << "FindFirstFile(" << dirPath << ") failed", FindFirstFile)); - } - return; - } - - do { - const tstring fname(findData.cFileName); - const tstring filePath = combinePath(dirPath, fname); - if (!isDirectoryAttrs(findData.dwFileAttributes)) { - if (!callback.onFile(filePath)) { - return; - } - } else if (fname != _T(".") && fname != _T("..")) { - if (!callback.onDirectory(filePath)) { - return; - } - } - } while (FindNextFile(h.get(), &findData)); - - // expect GetLastError() == ERROR_NO_MORE_FILES - if (GetLastError() != ERROR_NO_MORE_FILES) { - JP_THROW(SysError(tstrings::any() << "FindNextFile(" << dirPath << ") failed", FindNextFile)); - } -} - - -tstring replaceSuffix(const tstring& path, const tstring& newSuffix) { - return (path.substr(0, path.size() - suffix(path).size()) + newSuffix); -} - - -DirectoryIterator& DirectoryIterator::findItems(tstring_array& v) { - if (!isDirectory(root)) { - return *this; - } - - iterateDirectory(root, *this); - v.insert(v.end(), items.begin(), items.end()); - items = tstring_array(); - return *this; -} - -bool DirectoryIterator::onFile(const tstring& path) { - if (theWithFiles) { - items.push_back(path); - } - return true; -} - -bool DirectoryIterator::onDirectory(const tstring& path) { - if (theWithFolders) { - items.push_back(path); - } - if (theRecurse) { - DirectoryIterator(path).recurse(theRecurse) - .withFiles(theWithFiles) - .withFolders(theWithFolders) - .findItems(items); - } - return true; -} - - -namespace { - -struct DeleterFunctor { - // Order of items in the following enum is important! - // It controls order in which items of particular type will be deleted. - // See Deleter::execute(). - enum { - File, - FilesInDirectory, - RecursiveDirectory, - EmptyDirectory - }; - - void operator () (const Deleter::Path& path) const { - switch (path.second) { -#define DELETE_SOME(o, f)\ - case o:\ - f(path.first, std::nothrow);\ - break - - DELETE_SOME(File, deleteFile); - DELETE_SOME(EmptyDirectory, deleteDirectory); - DELETE_SOME(FilesInDirectory, deleteFilesInDirectory); - DELETE_SOME(RecursiveDirectory, deleteDirectoryRecursive); - -#undef DELETE_SOME - default: - break; - } - } -}; - -} // namespace - -void Deleter::execute() { - Paths tmp; - tmp.swap(paths); - - // Reorder items to delete. - std::stable_sort(tmp.begin(), tmp.end(), [] (const Paths::value_type& a, - const Paths::value_type& b) { - return a.second < b.second; - }); - - std::for_each(tmp.begin(), tmp.end(), DeleterFunctor()); -} - -Deleter& Deleter::appendFile(const tstring& path) { - paths.push_back(std::make_pair(path, DeleterFunctor::File)); - return *this; -} - -Deleter& Deleter::appendEmptyDirectory(const Directory& dir) { - tstring path = normalizePath(removeTrailingSlash(dir)); - const tstring parent = normalizePath(removeTrailingSlash(dir.parent)); - while(parent != path) { - appendEmptyDirectory(path); - path = dirname(path); - } - - return *this; -} - -Deleter& Deleter::appendEmptyDirectory(const tstring& path) { - paths.push_back(std::make_pair(path, - DeleterFunctor::EmptyDirectory)); - return *this; -} - -Deleter& Deleter::appendAllFilesInDirectory(const tstring& path) { - paths.push_back(std::make_pair(path, - DeleterFunctor::FilesInDirectory)); - return *this; -} - -Deleter& Deleter::appendRecursiveDirectory(const tstring& path) { - paths.push_back(std::make_pair(path, - DeleterFunctor::RecursiveDirectory)); - return *this; -} - - -FileWriter::FileWriter(const tstring& path): dstPath(path) { - tmpFile = FileUtils::createTempFile(_T("jds"), _T(".tmp"), - FileUtils::dirname(path)); - - cleaner.appendFile(tmpFile); - - // we want to get exception on error - tmp.exceptions(std::ifstream::failbit | std::ifstream::badbit); - tmp.open(tmpFile, std::ios::binary | std::ios::trunc); -} - -FileWriter& FileWriter::write(const void* buf, size_t bytes) { - tmp.write(static_cast(buf), bytes); - return *this; -} - -void FileWriter::finalize() { - tmp.close(); - - FileUtils::moveFile(tmpFile, dstPath, false); - - // cancel file deletion - cleaner.cancel(); -} - -} // namespace FileUtils +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include + +#include "FileUtils.h" +#include "WinErrorHandling.h" +#include "Log.h" + + +// Needed by FileUtils::isDirectoryNotEmpty +#pragma comment(lib, "shlwapi") + + +namespace FileUtils { + +namespace { + + +tstring reservedFilenameChars() { + tstring buf; + for (char charCode = 0; charCode < 32; ++charCode) { + buf.append(1, charCode); + } + buf += _T("<>:\"|?*/\\"); + return buf; +} + +} // namespace + +bool isDirSeparator(const tstring::value_type c) { + return (c == '/' || c == '\\'); +} + +bool isFileExists(const tstring &filePath) { + return GetFileAttributes(filePath.c_str()) != INVALID_FILE_ATTRIBUTES; +} + +namespace { +bool isDirectoryAttrs(const DWORD attrs) { + return attrs != INVALID_FILE_ATTRIBUTES + && (attrs & FILE_ATTRIBUTE_DIRECTORY) != 0; +} +} // namespace + +bool isDirectory(const tstring &filePath) { + return isDirectoryAttrs(GetFileAttributes(filePath.c_str())); +} + +bool isDirectoryNotEmpty(const tstring &dirPath) { + if (!isDirectory(dirPath)) { + return false; + } + return FALSE == PathIsDirectoryEmpty(dirPath.c_str()); +} + +tstring dirname(const tstring &path) { + tstring::size_type pos = path.find_last_of(_T("\\/")); + if (pos != tstring::npos) { + pos = path.find_last_not_of(_T("\\/"), pos); // skip trailing slashes + } + return pos == tstring::npos ? tstring() : path.substr(0, pos + 1); +} + +tstring basename(const tstring &path) { + const tstring::size_type pos = path.find_last_of(_T("\\/")); + if (pos == tstring::npos) { + return path; + } + return path.substr(pos + 1); +} + +tstring suffix(const tstring &path) { + const tstring::size_type pos = path.rfind('.'); + if (pos == tstring::npos) { + return tstring(); + } + const tstring::size_type dirSepPos = path.find_first_of(_T("\\/"), + pos + 1); + if (dirSepPos != tstring::npos) { + return tstring(); + } + // test for '/..' and '..' cases + if (pos != 0 && path[pos - 1] == '.' + && (pos == 1 || isDirSeparator(path[pos - 2]))) { + return tstring(); + } + return path.substr(pos); +} + +tstring combinePath(const tstring& parent, const tstring& child) { + if (parent.empty()) { + return child; + } + if (child.empty()) { + return parent; + } + + tstring parentWOSlash = removeTrailingSlash(parent); + // also handle the case when child contains starting slash + bool childHasSlash = isDirSeparator(child.front()); + tstring childWOSlash = childHasSlash ? child.substr(1) : child; + + return parentWOSlash + _T("\\") + childWOSlash; +} + +tstring removeTrailingSlash(const tstring& path) { + if (path.empty()) { + return path; + } + tstring::const_reverse_iterator it = path.rbegin(); + tstring::const_reverse_iterator end = path.rend(); + + while (it != end && isDirSeparator(*it)) { + ++it; + } + return path.substr(0, end - it); +} + +tstring normalizePath(tstring v) { + std::replace(v.begin(), v.end(), '/', '\\'); + return tstrings::toLower(v); +} + +namespace { + +bool createNewFile(const tstring& path) { + HANDLE h = CreateFile(path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, NULL); + // if the file exists => h == INVALID_HANDLE_VALUE & GetLastError + // returns ERROR_FILE_EXISTS + if (h != INVALID_HANDLE_VALUE) { + CloseHandle(h); + LOG_TRACE(tstrings::any() << "Created [" << path << "] file"); + return true; + } + return false; +} + +} // namespace + +tstring createTempFile(const tstring &prefix, const tstring &suffix, + const tstring &path) { + const tstring invalidChars = reservedFilenameChars(); + + if (prefix.find_first_of(invalidChars) != tstring::npos) { + JP_THROW(tstrings::any() << "Illegal characters in prefix=" << prefix); + } + + if (suffix.find_first_of(invalidChars) != tstring::npos) { + JP_THROW(tstrings::any() << "Illegal characters in suffix=" << suffix); + } + + int rnd = (int)GetTickCount(); + + // do no more than 100 attempts + for (int i=0; i<100; i++) { + const tstring filePath = mkpath() << path << (prefix + + (tstrings::any() << (rnd + i)).tstr() + suffix); + if (createNewFile(filePath)) { + return filePath; + } + } + + // 100 attempts failed + JP_THROW(tstrings::any() << "createTempFile(" << prefix << ", " + << suffix << ", " + << path << ") failed"); +} + +tstring createTempDirectory(const tstring &prefix, const tstring &suffix, + const tstring &basedir) { + const tstring filePath = createTempFile(prefix, suffix, basedir); + // delete the file and create directory with the same name + deleteFile(filePath); + createDirectory(filePath); + return filePath; +} + +tstring createUniqueFile(const tstring &prototype) { + if (createNewFile(prototype)) { + return prototype; + } + + return createTempFile(replaceSuffix(basename(prototype)), + suffix(prototype), dirname(prototype)); +} + +namespace { + +void createDir(const tstring path, LPSECURITY_ATTRIBUTES saAttr, + tstring_array* createdDirs=0) { + if (CreateDirectory(path.c_str(), saAttr)) { + LOG_TRACE(tstrings::any() << "Created [" << path << "] directory"); + if (createdDirs) { + createdDirs->push_back(removeTrailingSlash(path)); + } + } else { + const DWORD createDirectoryErr = GetLastError(); + // if saAttr is specified, fail even if the directory exists + if (saAttr != NULL || !isDirectory(path)) { + JP_THROW(SysError(tstrings::any() << "CreateDirectory(" + << path << ") failed", CreateDirectory, createDirectoryErr)); + } + } +} + +} + +void createDirectory(const tstring &path, tstring_array* createdDirs) { + const tstring dirPath = removeTrailingSlash(path) + _T("\\"); + + tstring::size_type pos = dirPath.find_first_of(_T("\\/")); + while (pos != tstring::npos) { + const tstring subdirPath = dirPath.substr(0, pos + 1); + createDir(subdirPath, NULL, createdDirs); + pos = dirPath.find_first_of(_T("\\/"), pos + 1); + } +} + + +void copyFile(const tstring& fromPath, const tstring& toPath, + bool failIfExists) { + createDirectory(dirname(toPath)); + if (!CopyFile(fromPath.c_str(), toPath.c_str(), + (failIfExists ? TRUE : FALSE))) { + JP_THROW(SysError(tstrings::any() + << "CopyFile(" << fromPath << ", " << toPath << ", " + << failIfExists << ") failed", CopyFile)); + } + LOG_TRACE(tstrings::any() << "Copied [" << fromPath << "] file to [" + << toPath << "]"); +} + + +namespace { + +void moveFileImpl(const tstring& fromPath, const tstring& toPath, + DWORD flags) { + const bool isDir = isDirectory(fromPath); + if (!MoveFileEx(fromPath.c_str(), toPath.empty() ? NULL : toPath.c_str(), + flags)) { + JP_THROW(SysError(tstrings::any() << "MoveFileEx(" << fromPath + << ", " << toPath << ", " << flags << ") failed", MoveFileEx)); + } + + const bool onReboot = 0 != (flags & MOVEFILE_DELAY_UNTIL_REBOOT); + + const LPCTSTR label = isDir ? _T("folder") : _T("file"); + + tstrings::any msg; + if (!toPath.empty()) { + if (onReboot) { + msg << "Move"; + } else { + msg << "Moved"; + } + msg << " '" << fromPath << "' " << label << " to '" << toPath << "'"; + } else { + if (onReboot) { + msg << "Delete"; + } else { + msg << "Deleted"; + } + msg << " '" << fromPath << "' " << label; + } + if (onReboot) { + msg << " on reboot"; + } + LOG_TRACE(msg); +} + +} // namespace + + +void moveFile(const tstring& fromPath, const tstring& toPath, + bool failIfExists) { + createDirectory(dirname(toPath)); + + DWORD flags = MOVEFILE_COPY_ALLOWED; + if (!failIfExists) { + flags |= MOVEFILE_REPLACE_EXISTING; + } + + moveFileImpl(fromPath, toPath, flags); +} + +void deleteFile(const tstring &path) +{ + if (!deleteFile(path, std::nothrow)) { + JP_THROW(SysError(tstrings::any() + << "DeleteFile(" << path << ") failed", DeleteFile)); + } +} + +namespace { + +bool notFound(const DWORD status=GetLastError()) { + return status == ERROR_FILE_NOT_FOUND || status == ERROR_PATH_NOT_FOUND; +} + +bool deleteFileImpl(const std::nothrow_t &, const tstring &path) { + const bool deleted = (DeleteFile(path.c_str()) != 0); + if (deleted) { + LOG_TRACE(tstrings::any() << "Deleted [" << path << "] file"); + return true; + } + return notFound(); +} + +} // namespace + +bool deleteFile(const tstring &path, const std::nothrow_t &) throw() +{ + bool deleted = deleteFileImpl(std::nothrow, path); + const DWORD status = GetLastError(); + if (!deleted && status == ERROR_ACCESS_DENIED) { + DWORD attrs = GetFileAttributes(path.c_str()); + SetLastError(status); + if (attrs == INVALID_FILE_ATTRIBUTES) { + return false; + } + if (attrs & FILE_ATTRIBUTE_READONLY) { + // DeleteFile() failed because file is R/O. + // Remove R/O attribute and retry DeleteFile(). + attrs &= ~FILE_ATTRIBUTE_READONLY; + if (SetFileAttributes(path.c_str(), attrs)) { + LOG_TRACE(tstrings::any() << "Discarded R/O attribute from [" + << path << "] file"); + deleted = deleteFileImpl(std::nothrow, path); + } else { + LOG_WARNING(SysError(tstrings::any() + << "Failed to discard R/O attribute from [" + << path << "] file. File will not be deleted", + SetFileAttributes).what()); + SetLastError(status); + } + } + } + + return deleted || notFound(); +} + +void deleteDirectory(const tstring &path) +{ + if (!deleteDirectory(path, std::nothrow)) { + JP_THROW(SysError(tstrings::any() + << "RemoveDirectory(" << path << ") failed", RemoveDirectory)); + } +} + +bool deleteDirectory(const tstring &path, const std::nothrow_t &) throw() +{ + const bool deleted = (RemoveDirectory(path.c_str()) != 0); + if (deleted) { + LOG_TRACE(tstrings::any() << "Deleted [" << path << "] directory"); + } + return deleted || notFound(); +} + +namespace { + +class DeleteFilesCallback: public DirectoryCallback { +public: + explicit DeleteFilesCallback(bool ff): failfast(ff), failed(false) { + } + + virtual bool onFile(const tstring& path) { + if (failfast) { + deleteFile(path); + } else { + updateStatus(deleteFile(path, std::nothrow)); + } + return true; + } + + bool good() const { + return !failed; + } + +protected: + void updateStatus(bool success) { + if (!success) { + failed = true; + } + } + + const bool failfast; +private: + bool failed; +}; + +class DeleteAllCallback: public DeleteFilesCallback { +public: + explicit DeleteAllCallback(bool failfast): DeleteFilesCallback(failfast) { + } + + virtual bool onDirectory(const tstring& path) { + if (failfast) { + deleteDirectoryRecursive(path); + } else { + updateStatus(deleteDirectoryRecursive(path, std::nothrow)); + } + return true; + } +}; + + +class BatchDeleter { + const tstring dirPath; + bool recursive; +public: + explicit BatchDeleter(const tstring& path): dirPath(path) { + deleteSubdirs(false); + } + + BatchDeleter& deleteSubdirs(bool v) { + recursive = v; + return *this; + } + + void execute() const { + if (!isFileExists(dirPath)) { + return; + } + iterateDirectory(true /* fail fast */); + if (recursive) { + deleteDirectory(dirPath); + } + } + + bool execute(const std::nothrow_t&) const { + if (!isFileExists(dirPath)) { + return true; + } + + if (!isDirectory(dirPath)) { + return false; + } + + JP_TRY; + if (!iterateDirectory(false /* ignore errors */)) { + return false; + } + if (recursive) { + return deleteDirectory(dirPath, std::nothrow); + } + return true; + JP_CATCH_ALL; + + return false; + } + +private: + bool iterateDirectory(bool failfast) const { + std::unique_ptr callback; + if (recursive) { + callback = std::unique_ptr( + new DeleteAllCallback(failfast)); + } else { + callback = std::unique_ptr( + new DeleteFilesCallback(failfast)); + } + + FileUtils::iterateDirectory(dirPath, *callback); + return callback->good(); + } +}; + +} // namespace + +void deleteFilesInDirectory(const tstring &dirPath) { + BatchDeleter(dirPath).execute(); +} + +bool deleteFilesInDirectory(const tstring &dirPath, + const std::nothrow_t &) throw() { + return BatchDeleter(dirPath).execute(std::nothrow); +} + +void deleteDirectoryRecursive(const tstring &dirPath) { + BatchDeleter(dirPath).deleteSubdirs(true).execute(); +} + +bool deleteDirectoryRecursive(const tstring &dirPath, + const std::nothrow_t &) throw() { + return BatchDeleter(dirPath).deleteSubdirs(true).execute(std::nothrow); +} + +namespace { + +struct FindFileDeleter { + typedef HANDLE pointer; + + void operator()(HANDLE h) { + if (h && h != INVALID_HANDLE_VALUE) { + FindClose(h); + } + } +}; + +typedef std::unique_ptr UniqueFindFileHandle; + +}; // namesace +void iterateDirectory(const tstring &dirPath, DirectoryCallback& callback) +{ + const tstring searchString = combinePath(dirPath, _T("*")); + WIN32_FIND_DATA findData; + UniqueFindFileHandle h(FindFirstFile(searchString.c_str(), &findData)); + if (h.get() == INVALID_HANDLE_VALUE) { + // GetLastError() == ERROR_FILE_NOT_FOUND is OK + // - no files in the directory + // ERROR_PATH_NOT_FOUND is returned + // if the parent directory does not exist + if (GetLastError() != ERROR_FILE_NOT_FOUND) { + JP_THROW(SysError(tstrings::any() << "FindFirstFile(" + << dirPath << ") failed", FindFirstFile)); + } + return; + } + + do { + const tstring fname(findData.cFileName); + const tstring filePath = combinePath(dirPath, fname); + if (!isDirectoryAttrs(findData.dwFileAttributes)) { + if (!callback.onFile(filePath)) { + return; + } + } else if (fname != _T(".") && fname != _T("..")) { + if (!callback.onDirectory(filePath)) { + return; + } + } + } while (FindNextFile(h.get(), &findData)); + + // expect GetLastError() == ERROR_NO_MORE_FILES + if (GetLastError() != ERROR_NO_MORE_FILES) { + JP_THROW(SysError(tstrings::any() << "FindNextFile(" + << dirPath << ") failed", FindNextFile)); + } +} + + +tstring replaceSuffix(const tstring& path, const tstring& newSuffix) { + return (path.substr(0, path.size() - suffix(path).size()) + newSuffix); +} + + +DirectoryIterator& DirectoryIterator::findItems(tstring_array& v) { + if (!isDirectory(root)) { + return *this; + } + + iterateDirectory(root, *this); + v.insert(v.end(), items.begin(), items.end()); + items = tstring_array(); + return *this; +} + +bool DirectoryIterator::onFile(const tstring& path) { + if (theWithFiles) { + items.push_back(path); + } + return true; +} + +bool DirectoryIterator::onDirectory(const tstring& path) { + if (theWithFolders) { + items.push_back(path); + } + if (theRecurse) { + DirectoryIterator(path).recurse(theRecurse) + .withFiles(theWithFiles) + .withFolders(theWithFolders) + .findItems(items); + } + return true; +} + + +namespace { + +struct DeleterFunctor { + // Order of items in the following enum is important! + // It controls order in which items of particular type will be deleted. + // See Deleter::execute(). + enum { + File, + FilesInDirectory, + RecursiveDirectory, + EmptyDirectory + }; + + void operator () (const Deleter::Path& path) const { + switch (path.second) { +#define DELETE_SOME(o, f)\ + case o:\ + f(path.first, std::nothrow);\ + break + + DELETE_SOME(File, deleteFile); + DELETE_SOME(EmptyDirectory, deleteDirectory); + DELETE_SOME(FilesInDirectory, deleteFilesInDirectory); + DELETE_SOME(RecursiveDirectory, deleteDirectoryRecursive); + +#undef DELETE_SOME + default: + break; + } + } +}; + +} // namespace + +void Deleter::execute() { + Paths tmp; + tmp.swap(paths); + + // Reorder items to delete. + std::stable_sort(tmp.begin(), tmp.end(), [] (const Paths::value_type& a, + const Paths::value_type& b) { + return a.second < b.second; + }); + + std::for_each(tmp.begin(), tmp.end(), DeleterFunctor()); +} + +Deleter& Deleter::appendFile(const tstring& path) { + paths.push_back(std::make_pair(path, DeleterFunctor::File)); + return *this; +} + +Deleter& Deleter::appendEmptyDirectory(const Directory& dir) { + tstring path = normalizePath(removeTrailingSlash(dir)); + const tstring parent = normalizePath(removeTrailingSlash(dir.parent)); + while(parent != path) { + appendEmptyDirectory(path); + path = dirname(path); + } + + return *this; +} + +Deleter& Deleter::appendEmptyDirectory(const tstring& path) { + paths.push_back(std::make_pair(path, DeleterFunctor::EmptyDirectory)); + return *this; +} + +Deleter& Deleter::appendAllFilesInDirectory(const tstring& path) { + paths.push_back(std::make_pair(path, DeleterFunctor::FilesInDirectory)); + return *this; +} + +Deleter& Deleter::appendRecursiveDirectory(const tstring& path) { + paths.push_back(std::make_pair(path, DeleterFunctor::RecursiveDirectory)); + return *this; +} + + +FileWriter::FileWriter(const tstring& path): dstPath(path) { + tmpFile = FileUtils::createTempFile(_T("jds"), _T(".tmp"), + FileUtils::dirname(path)); + + cleaner.appendFile(tmpFile); + + // we want to get exception on error + tmp.exceptions(std::ifstream::failbit | std::ifstream::badbit); + tmp.open(tmpFile, std::ios::binary | std::ios::trunc); +} + +FileWriter& FileWriter::write(const void* buf, size_t bytes) { + tmp.write(static_cast(buf), bytes); + return *this; +} + +void FileWriter::finalize() { + tmp.close(); + + FileUtils::moveFile(tmpFile, dstPath, false); + + // cancel file deletion + cleaner.cancel(); +} + +} // namespace FileUtils --- old/src/jdk.jpackage/windows/native/libjpackage/FileUtils.h 2019-08-28 09:05:30.735266200 -0400 +++ new/src/jdk.jpackage/windows/native/libjpackage/FileUtils.h 2019-08-28 09:05:28.707227200 -0400 @@ -43,13 +43,15 @@ // returns false if the path does not exist bool isDirectory(const tstring &filePath); - //checks if the specified directory is not empty - //returns true if the path is an existing directory and it contains at least one file other than "." or "..". + // checks if the specified directory is not empty + // returns true if the path is an existing directory and + // it contains at least one file other than "." or "..". bool isDirectoryNotEmpty(const tstring &dirPath); // returns directory part of the path. // returns empty string if the path contains only filename. - // if the path ends with slash/backslash, returns removeTrailingSlashes(path). + // if the path ends with slash/backslash, + // returns removeTrailingSlashes(path). tstring dirname(const tstring &path); // returns basename part of the path @@ -73,18 +75,24 @@ // removes trailing slashes and backslashes in the path if any tstring removeTrailingSlash(const tstring& path); - // Creates a file with unique name in the specified base directory, throws an exception if operation fails + // Creates a file with unique name in the specified base directory, + // throws an exception if operation fails // path is constructed as . // The function fails and throws exception if 'path' doesn't exist. - tstring createTempFile(const tstring &prefix = _T(""), const tstring &suffix = _T(".tmp"), const tstring &path=SysInfo::getTempDir()); + tstring createTempFile(const tstring &prefix = _T(""), + const tstring &suffix = _T(".tmp"), + const tstring &path=SysInfo::getTempDir()); - // Creates a directory with unique name in the specified base directory, throws an exception if operation fails + // Creates a directory with unique name in the specified base directory, + // throws an exception if operation fails // path is constructed as // The function fails and throws exception if 'path' doesn't exist. - tstring createTempDirectory(const tstring &prefix = _T(""), const tstring &suffix = _T(".tmp"), const tstring &basedir=SysInfo::getTempDir()); + tstring createTempDirectory(const tstring &prefix = _T(""), + const tstring &suffix = _T(".tmp"), + const tstring &basedir=SysInfo::getTempDir()); - // If the file referenced with "prototype" parameter DOES NOT exist, the return - // value is the given path. No new files created. + // If the file referenced with "prototype" parameter DOES NOT exist, + // the return value is the given path. No new files created. // Otherwise the function creates another file in the same directory as // the given file with the same suffix and with the basename from the // basename of the given file with some random chars appended to ensure @@ -97,11 +105,15 @@ // all subdirectories created by this function call. void createDirectory(const tstring &path, tstring_array* createdDirs=0); - // copies file from fromPath to toPath. Creates output directory if doesn't exist. - void copyFile(const tstring& fromPath, const tstring& toPath, bool failIfExists); - - // moves file from fromPath to toPath. Creates output directory if doesn't exist. - void moveFile(const tstring& fromPath, const tstring& toPath, bool failIfExists); + // copies file from fromPath to toPath. + // Creates output directory if doesn't exist. + void copyFile(const tstring& fromPath, const tstring& toPath, + bool failIfExists); + + // moves file from fromPath to toPath. + // Creates output directory if doesn't exist. + void moveFile(const tstring& fromPath, const tstring& toPath, + bool failIfExists); // Throws exception if fails to delete specified 'path'. // Exits normally if 'path' doesn't exist or it has been deleted. @@ -131,10 +143,12 @@ // 'dirPath' directory. // Doesn't abort iteration over files if the given directory after the // first failure to delete a file. - bool deleteFilesInDirectory(const tstring &dirPath, const std::nothrow_t &) throw(); + bool deleteFilesInDirectory(const tstring &dirPath, + const std::nothrow_t &) throw(); // Like deleteFilesInDirectory, but deletes subdirectories as well void deleteDirectoryRecursive(const tstring &dirPath); - bool deleteDirectoryRecursive(const tstring &dirPath, const std::nothrow_t &) throw(); + bool deleteDirectoryRecursive(const tstring &dirPath, + const std::nothrow_t &) throw(); class DirectoryCallback { public: @@ -201,9 +215,12 @@ tstring_array items; }; - // Returns array of all the files/sub-folders from the given directory, empty array if basedir is not a directory. The returned - // array is ordered from top down (i.e. dirs are listed first followed by subfolders and files). - // Order of subfolders and files is undefined but usually they are sorted by names. + // Returns array of all the files/sub-folders from the given directory, + // empty array if basedir is not a directory. The returned + // array is ordered from top down (i.e. dirs are listed first followed + // by subfolders and files). + // Order of subfolders and files is undefined + // but usually they are sorted by names. inline tstring_array listAllContents(const tstring& basedir) { return DirectoryIterator(basedir).findItems(); } @@ -240,7 +257,8 @@ Directory() { } - Directory(const tstring &parent, const tstring &subdir) : parent(parent), subdir(subdir) { + Directory(const tstring &parent, + const tstring &subdir) : parent(parent), subdir(subdir) { } operator tstring () const { @@ -313,11 +331,13 @@ return *this; } - // Schedule empty directory for deletion with empty roots (up to Directory.parent). + // Schedule empty directory for deletion with empty roots + // (up to Directory.parent). Deleter& appendEmptyDirectory(const Directory& dir); // Schedule empty directory for deletion without roots. - // This is a particular case of appendEmptyDirectory(const Directory& dir) + // This is a particular case of + // appendEmptyDirectory(const Directory& dir) // with Directory(dirname(path), basename(path)). Deleter& appendEmptyDirectory(const tstring& path); --- old/src/jdk.jpackage/windows/native/libjpackage/IconSwap.cpp 2019-08-28 09:06:21.205638300 -0400 +++ new/src/jdk.jpackage/windows/native/libjpackage/IconSwap.cpp 2019-08-28 09:06:18.707590100 -0400 @@ -83,8 +83,9 @@ LPVOID message = NULL; DWORD error = GetLastError(); - if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, + if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER + | FORMAT_MESSAGE_FROM_SYSTEM + | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) & message, 0, NULL) != 0) { printf("%S", (LPTSTR) message); @@ -184,9 +185,9 @@ free(lpid); CloseHandle(icon); - if (!UpdateResource(update, RT_GROUP_ICON, - MAKEINTRESOURCE(1), language, &lpgid[0], - (sizeof (WORD) * 3) + (sizeof (GRPICONDIRENTRY) * lpgid->idCount))) { + if (!UpdateResource(update, RT_GROUP_ICON, MAKEINTRESOURCE(1), + language, &lpgid[0], (sizeof (WORD) * 3) + + (sizeof (GRPICONDIRENTRY) * lpgid->idCount))) { free(lpgid); PrintError(); return false; --- old/src/jdk.jpackage/windows/native/libjpackage/Log.cpp 2019-08-28 09:06:41.697833100 -0400 +++ new/src/jdk.jpackage/windows/native/libjpackage/Log.cpp 2019-08-28 09:06:37.734356800 -0400 @@ -98,8 +98,7 @@ /*static*/ -Logger& Logger::defaultLogger() -{ +Logger& Logger::defaultLogger() { Logger* reply = reinterpret_cast(defaultLoggerMemory); if (!reply->appender) { @@ -121,9 +120,10 @@ std::memcpy(moduleName, mname.c_str(), mname.size()); moduleName[mname.size()] = TCHAR(0); - // if JPACKAGE_DEBUG environment variable is NOT set to "true" disable + // if JPACKAGE_DEBUG environment variable is NOT set to "true" disable // logging. - if (SysInfo::getEnvVariable(std::nothrow, L"JPACKAGE_DEBUG") != L"true") { + if (SysInfo::getEnvVariable(std::nothrow, + L"JPACKAGE_DEBUG") != L"true") { reply->appender = &nopLogApender; } @@ -134,31 +134,27 @@ } Logger::Logger(LogAppender& appender, LogLevel logLevel) - : level(logLevel), appender(&appender) -{ + : level(logLevel), appender(&appender) { } -void Logger::setLogLevel(LogLevel logLevel) -{ +void Logger::setLogLevel(LogLevel logLevel) { level = logLevel; } -Logger::~Logger() -{ +Logger::~Logger() { } -bool Logger::isLoggable(LogLevel logLevel) const -{ +bool Logger::isLoggable(LogLevel logLevel) const { return logLevel >= level; } -void Logger::log(LogLevel logLevel, LPCTSTR fileName, int lineNum, LPCTSTR funcName, const tstring& message) const -{ +void Logger::log(LogLevel logLevel, LPCTSTR fileName, int lineNum, + LPCTSTR funcName, const tstring& message) const { LogEvent logEvent; - // [YYYY/MM/DD HH:MM:SS.ms, (PID: processID, TID: threadID), fileName:lineNum (funcName)] - // LEVEL: message + // [YYYY/MM/DD HH:MM:SS.ms, (PID: processID, TID: threadID), + // fileName:lineNum (funcName)] LEVEL: message GetLocalTime(&logEvent.ts); logEvent.pid = GetCurrentProcessId(); @@ -177,8 +173,9 @@ void StderrLogAppender::append(const LogEvent& v) { const tstring out = tstrings::unsafe_format(format, - unsigned(v.ts.wYear), unsigned(v.ts.wMonth), unsigned(v.ts.wDay), // date - unsigned(v.ts.wHour), unsigned(v.ts.wMinute), unsigned(v.ts.wSecond), unsigned(v.ts.wMilliseconds), // time + unsigned(v.ts.wYear), unsigned(v.ts.wMonth), unsigned(v.ts.wDay), + unsigned(v.ts.wHour), unsigned(v.ts.wMinute), unsigned(v.ts.wSecond), + unsigned(v.ts.wMilliseconds), v.moduleName.c_str(), v.pid, v.tid, v.fileName.c_str(), v.lineNum, v.funcName.c_str(), v.logLevel.c_str(), @@ -189,11 +186,14 @@ // Logger::ScopeTracer -Logger::ScopeTracer::ScopeTracer(Logger &logger, LogLevel logLevel, LPCTSTR fileName, int lineNum, LPCTSTR funcName, const tstring& scopeName) - : log(logger), level(logLevel), file(fileName), line(lineNum), func(funcName), scope(scopeName), needLog(logger.isLoggable(logLevel)) -{ +Logger::ScopeTracer::ScopeTracer(Logger &logger, LogLevel logLevel, + LPCTSTR fileName, int lineNum, LPCTSTR funcName, + const tstring& scopeName) : log(logger), level(logLevel), + file(fileName), line(lineNum), + func(funcName), scope(scopeName), needLog(logger.isLoggable(logLevel)) { if (needLog) { - log.log(level, file.c_str(), line, func.c_str(), tstrings::any() << "Entering " << scope); + log.log(level, file.c_str(), line, func.c_str(), + tstrings::any() << "Entering " << scope); } } @@ -202,6 +202,7 @@ // we don't know what line is end of scope at, so specify line 0 // and add note about line when the scope begins log.log(level, file.c_str(), 0, func.c_str(), - tstrings::any() << "Exiting " << scope << " (entered at " << FileUtils::basename(file) << ":" << line << ")"); + tstrings::any() << "Exiting " << scope << " (entered at " + << FileUtils::basename(file) << ":" << line << ")"); } } --- old/src/jdk.jpackage/windows/native/libjpackage/Log.h 2019-08-28 09:07:28.779939800 -0400 +++ new/src/jdk.jpackage/windows/native/libjpackage/Log.h 2019-08-28 09:07:26.188289800 -0400 @@ -30,19 +30,21 @@ #include "tstrings.h" -/* Default logger (Logger::defaultLogger()) writes log messages to the default log file. +/* Default logger (Logger::defaultLogger()) writes log messages to + * the default log file. * Common scenario: * - main() function configures default logger: * FileLogAppender appender(_T("my_log_filename.log")); * Logger::defaultLogger().setAppender(appender); * Logger::defaultLogger().setLogLevel(LOG_INFO); - * If the default file name and log level are not set, _T("jusched.log")/LOG_TRACE are used. + * If the default file name and log level are not set, + * _T("jusched.log")/LOG_TRACE are used. * * Logger fileName specifies only file name, - * full path for the log file depends on the platform (usually value of the TMP env. var) + * full path for the log file depends on the platform + * (usually value of the TMP env. var) */ - struct LogEvent { SYSTEMTIME ts; long tid; @@ -75,7 +77,7 @@ class TeeLogAppender: public LogAppender { public: TeeLogAppender(LogAppender* first, LogAppender* second): - first(first), second(second) { + first(first), second(second) { } virtual ~TeeLogAppender() { } @@ -131,20 +133,22 @@ void setLogLevel(LogLevel logLevel); bool isLoggable(LogLevel logLevel) const ; - void log(LogLevel logLevel, LPCTSTR fileName, int lineNum, LPCTSTR funcName, const tstring& message) const; void log(LogLevel logLevel, LPCTSTR fileName, int lineNum, - LPCTSTR funcName, const tstrings::any& message) const { + LPCTSTR funcName, const tstring& message) const; + void log(LogLevel logLevel, LPCTSTR fileName, int lineNum, + LPCTSTR funcName, const tstrings::any& message) const { return log(logLevel, fileName, lineNum, funcName, message.tstr()); } void log(LogLevel logLevel, LPCTSTR fileName, int lineNum, - LPCTSTR funcName, tstring::const_pointer message) const { + LPCTSTR funcName, tstring::const_pointer message) const { return log(logLevel, fileName, lineNum, funcName, tstring(message)); } // internal class for scope tracing class ScopeTracer { public: - ScopeTracer(Logger &logger, LogLevel logLevel, LPCTSTR fileName, int lineNum, LPCTSTR funcName, const tstring& scopeName); + ScopeTracer(Logger &logger, LogLevel logLevel, LPCTSTR fileName, + int lineNum, LPCTSTR funcName, const tstring& scopeName); ~ScopeTracer(); private: --- old/src/jdk.jpackage/windows/native/libjpackage/ResourceEditor.cpp 2019-08-28 09:08:19.410315300 -0400 +++ new/src/jdk.jpackage/windows/native/libjpackage/ResourceEditor.cpp 2019-08-28 09:08:16.944467800 -0400 @@ -1,123 +1,123 @@ -/* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include -#include -#include "ResourceEditor.h" -#include "WinErrorHandling.h" -#include "Log.h" - - -ResourceEditor::FileLock::FileLock(const std::wstring& binaryPath) { - h = BeginUpdateResource(binaryPath.c_str(), FALSE); - if (NULL == h) { - JP_THROW(SysError(tstrings::any() << "BeginUpdateResource(" - << binaryPath << ") failed", BeginUpdateResource)); - } - - discard(false); -} - - -ResourceEditor::FileLock::~FileLock() { - if (!EndUpdateResource(h, theDiscard)) { - JP_NO_THROW(JP_THROW(SysError(tstrings::any() - << "EndUpdateResource(" << h << ") failed.", EndUpdateResource))); - } -} - - -ResourceEditor::ResourceEditor() { - language(MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)).type(unsigned(0)).id(unsigned(0)); -} - - -ResourceEditor& ResourceEditor::type(unsigned v) { - return type(MAKEINTRESOURCE(v)); -} - - -ResourceEditor& ResourceEditor::type(LPCWSTR v) { - if (IS_INTRESOURCE(v)) { - std::wostringstream printer; - printer << L"#" << reinterpret_cast(v); - theType = printer.str(); - theTypePtr = MAKEINTRESOURCE(static_cast(reinterpret_cast(v))); - } else { - theType = v; - theTypePtr = theType.c_str(); - } - return *this; -} - - -ResourceEditor& ResourceEditor::id(unsigned v) { - return id(MAKEINTRESOURCE(v)); -} - - -ResourceEditor& ResourceEditor::id(LPCWSTR v) { - if (IS_INTRESOURCE(v)) { - std::wostringstream printer; - printer << L"#" << reinterpret_cast(v); - theId = printer.str(); - } else { - theId = v; - theIdPtr = theId.c_str(); - } - return *this; -} - - -ResourceEditor& ResourceEditor::apply(const FileLock& dstBinary, - std::istream& srcStream, std::streamsize size) { - - typedef std::vector ByteArray; - ByteArray buf; - if (size <= 0) { - // Read the entire stream. - buf = ByteArray((std::istreambuf_iterator(srcStream)), - std::istreambuf_iterator()); - } else { - buf.resize(size_t(size)); - srcStream.read(reinterpret_cast(buf.data()), size); - } - - auto reply = UpdateResource(dstBinary.get(), theTypePtr, theIdPtr, lang, - buf.data(), static_cast(buf.size())); - if (reply == FALSE) { - JP_THROW(SysError("UpdateResource() failed", UpdateResource)); - } - - return *this; -} - - -ResourceEditor& ResourceEditor::apply(const FileLock& dstBinary, - const std::wstring& srcFile) { - std::ifstream input(srcFile, std::ios_base::binary); - input.exceptions(std::ios::failbit | std::ios::badbit); - return apply(dstBinary, input); -} +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include +#include +#include "ResourceEditor.h" +#include "WinErrorHandling.h" +#include "Log.h" + + +ResourceEditor::FileLock::FileLock(const std::wstring& binaryPath) { + h = BeginUpdateResource(binaryPath.c_str(), FALSE); + if (NULL == h) { + JP_THROW(SysError(tstrings::any() << "BeginUpdateResource(" + << binaryPath << ") failed", BeginUpdateResource)); + } + + discard(false); +} + + +ResourceEditor::FileLock::~FileLock() { + if (!EndUpdateResource(h, theDiscard)) { + JP_NO_THROW(JP_THROW(SysError(tstrings::any() + << "EndUpdateResource(" << h << ") failed.", EndUpdateResource))); + } +} + + +ResourceEditor::ResourceEditor() { + language(MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)).type(unsigned(0)).id(unsigned(0)); +} + + +ResourceEditor& ResourceEditor::type(unsigned v) { + return type(MAKEINTRESOURCE(v)); +} + + +ResourceEditor& ResourceEditor::type(LPCWSTR v) { + if (IS_INTRESOURCE(v)) { + std::wostringstream printer; + printer << L"#" << reinterpret_cast(v); + theType = printer.str(); + theTypePtr = MAKEINTRESOURCE(static_cast(reinterpret_cast(v))); + } else { + theType = v; + theTypePtr = theType.c_str(); + } + return *this; +} + + +ResourceEditor& ResourceEditor::id(unsigned v) { + return id(MAKEINTRESOURCE(v)); +} + + +ResourceEditor& ResourceEditor::id(LPCWSTR v) { + if (IS_INTRESOURCE(v)) { + std::wostringstream printer; + printer << L"#" << reinterpret_cast(v); + theId = printer.str(); + } else { + theId = v; + theIdPtr = theId.c_str(); + } + return *this; +} + + +ResourceEditor& ResourceEditor::apply(const FileLock& dstBinary, + std::istream& srcStream, std::streamsize size) { + + typedef std::vector ByteArray; + ByteArray buf; + if (size <= 0) { + // Read the entire stream. + buf = ByteArray((std::istreambuf_iterator(srcStream)), + std::istreambuf_iterator()); + } else { + buf.resize(size_t(size)); + srcStream.read(reinterpret_cast(buf.data()), size); + } + + auto reply = UpdateResource(dstBinary.get(), theTypePtr, theIdPtr, lang, + buf.data(), static_cast(buf.size())); + if (reply == FALSE) { + JP_THROW(SysError("UpdateResource() failed", UpdateResource)); + } + + return *this; +} + + +ResourceEditor& ResourceEditor::apply(const FileLock& dstBinary, + const std::wstring& srcFile) { + std::ifstream input(srcFile, std::ios_base::binary); + input.exceptions(std::ios::failbit | std::ios::badbit); + return apply(dstBinary, input); +} --- old/src/jdk.jpackage/windows/native/libjpackage/ResourceEditor.h 2019-08-28 09:08:38.150276000 -0400 +++ new/src/jdk.jpackage/windows/native/libjpackage/ResourceEditor.h 2019-08-28 09:08:35.466024300 -0400 @@ -1,107 +1,107 @@ -/* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef RESOURCEEDITOR_H -#define RESOURCEEDITOR_H - -#include -#include -#include - - -class ResourceEditor { -public: - class FileLock { - public: - FileLock(const std::wstring& binaryPath); - ~FileLock(); - - HANDLE get() const { - return h; - } - - void discard(bool v = true) { - theDiscard = v; - } - - private: - FileLock(const FileLock&); - FileLock& operator=(const FileLock&); - private: - HANDLE h; - bool theDiscard; - }; - -public: - ResourceEditor(); - - /** - * Set the language identifier of the resource to be updated. - */ - ResourceEditor& language(unsigned v) { - lang = v; - return *this; - } - - /** - * Set the resource type to be updated. - */ - ResourceEditor& type(unsigned v); - - /** - * Set the resource type to be updated. - */ - ResourceEditor& type(LPCWSTR v); - - /** - * Set resource ID. - */ - ResourceEditor& id(unsigned v); - - /** - * Set resource ID. - */ - ResourceEditor& id(LPCWSTR v); - - /** - * Relaces resource configured in the given binary with the given data stream. - */ - ResourceEditor& apply(const FileLock& dstBinary, std::istream& srcStream, std::streamsize size=0); - - /** - * Relaces resource configured in the given binary with contents of - * the given binary file. - */ - ResourceEditor& apply(const FileLock& dstBinary, const std::wstring& srcFile); - -private: - unsigned lang; - std::wstring theId; - LPCWSTR theIdPtr; - std::wstring theType; - LPCWSTR theTypePtr; -}; - -#endif // #ifndef RESOURCEEDITOR_H +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef RESOURCEEDITOR_H +#define RESOURCEEDITOR_H + +#include +#include +#include + + +class ResourceEditor { +public: + class FileLock { + public: + FileLock(const std::wstring& binaryPath); + ~FileLock(); + + HANDLE get() const { + return h; + } + + void discard(bool v = true) { + theDiscard = v; + } + + private: + FileLock(const FileLock&); + FileLock& operator=(const FileLock&); + private: + HANDLE h; + bool theDiscard; + }; + +public: + ResourceEditor(); + + /** + * Set the language identifier of the resource to be updated. + */ + ResourceEditor& language(unsigned v) { + lang = v; + return *this; + } + + /** + * Set the resource type to be updated. + */ + ResourceEditor& type(unsigned v); + + /** + * Set the resource type to be updated. + */ + ResourceEditor& type(LPCWSTR v); + + /** + * Set resource ID. + */ + ResourceEditor& id(unsigned v); + + /** + * Set resource ID. + */ + ResourceEditor& id(LPCWSTR v); + + /** + * Relaces resource configured in the given binary with the given data stream. + */ + ResourceEditor& apply(const FileLock& dstBinary, std::istream& srcStream, std::streamsize size=0); + + /** + * Relaces resource configured in the given binary with contents of + * the given binary file. + */ + ResourceEditor& apply(const FileLock& dstBinary, const std::wstring& srcFile); + +private: + unsigned lang; + std::wstring theId; + LPCWSTR theIdPtr; + std::wstring theType; + LPCWSTR theTypePtr; +}; + +#endif // #ifndef RESOURCEEDITOR_H --- old/src/jdk.jpackage/windows/native/libjpackage/SysInfo.h 2019-08-28 09:08:59.121079600 -0400 +++ new/src/jdk.jpackage/windows/native/libjpackage/SysInfo.h 2019-08-28 09:08:55.563211100 -0400 @@ -61,10 +61,12 @@ /** * Retrieves the command-line arguments for the current process. * With IncludeProgramName option returns result similar to argv/argc. - * With ExcludeProgramName option program name (the 1st element of command line) + * With ExcludeProgramName option program name + * (the 1st element of command line) * is excluded. */ - tstring_array getCommandArgs(CommandArgProgramNameMode progNameMode = ExcludeProgramName); + tstring_array getCommandArgs( + CommandArgProgramNameMode progNameMode = ExcludeProgramName); /** * Returns value of environment variable with the given name. @@ -79,7 +81,7 @@ * other error occurred reading the value. */ tstring getEnvVariable(const std::nothrow_t&, const tstring& name, - const tstring& defValue=tstring()); + const tstring& defValue=tstring()); /** * Returns 'true' if environment variable with the given name is set. --- old/src/jdk.jpackage/windows/native/libjpackage/UniqueHandle.h 2019-08-28 09:09:19.360669300 -0400 +++ new/src/jdk.jpackage/windows/native/libjpackage/UniqueHandle.h 2019-08-28 09:09:16.443413200 -0400 @@ -1,43 +1,43 @@ -/* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef UNIQUEHANDLE_H -#define UNIQUEHANDLE_H - -#include -#include - - -struct WndHandleDeleter { - typedef HANDLE pointer; - - void operator()(HANDLE h) { - ::CloseHandle(h); - } -}; - -typedef std::unique_ptr UniqueHandle; - -#endif // #ifndef UNIQUEHANDLE_H +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef UNIQUEHANDLE_H +#define UNIQUEHANDLE_H + +#include +#include + + +struct WndHandleDeleter { + typedef HANDLE pointer; + + void operator()(HANDLE h) { + ::CloseHandle(h); + } +}; + +typedef std::unique_ptr UniqueHandle; + +#endif // #ifndef UNIQUEHANDLE_H --- old/src/jdk.jpackage/windows/native/libjpackage/Utils.cpp 2019-08-28 09:09:35.696584900 -0400 +++ new/src/jdk.jpackage/windows/native/libjpackage/Utils.cpp 2019-08-28 09:09:33.387740500 -0400 @@ -41,7 +41,8 @@ return wstr; } -jstring GetJStringFromString(JNIEnv *pEnv, const jchar *unicodeChars, jsize len) { +jstring GetJStringFromString(JNIEnv *pEnv, + const jchar *unicodeChars, jsize len) { return pEnv->NewString(unicodeChars, len); } @@ -64,7 +65,8 @@ delete [] pBuffer; pBuffer = new TCHAR[dwResult]; if (pBuffer != NULL) { - DWORD dwResult2 = GetLongPathName(path.c_str(), pBuffer, dwResult); + DWORD dwResult2 = + GetLongPathName(path.c_str(), pBuffer, dwResult); if (dwResult2 == (dwResult - 1)) { result = wstring(pBuffer); } --- old/src/jdk.jpackage/windows/native/libjpackage/Utils.h 2019-08-28 09:09:51.625491300 -0400 +++ new/src/jdk.jpackage/windows/native/libjpackage/Utils.h 2019-08-28 09:09:48.786236700 -0400 @@ -32,7 +32,8 @@ using namespace std; wstring GetStringFromJString(JNIEnv *pEnv, jstring jstr); -jstring GetJStringFromString(JNIEnv *pEnv, const jchar *unicodeChars, jsize len); +jstring GetJStringFromString(JNIEnv *pEnv, const jchar *unicodeChars, + jsize len); wstring GetLongPath(wstring path); --- old/src/jdk.jpackage/windows/native/libjpackage/VersionInfoSwap.cpp 2019-08-28 09:10:36.120948500 -0400 +++ new/src/jdk.jpackage/windows/native/libjpackage/VersionInfoSwap.cpp 2019-08-28 09:10:32.422677300 -0400 @@ -52,7 +52,8 @@ * the existing version resource will be replaced with new one. */ -VersionInfoSwap::VersionInfoSwap(wstring executableProperties, wstring launcher) { +VersionInfoSwap::VersionInfoSwap(wstring executableProperties, + wstring launcher) { m_executableProperties = executableProperties; m_launcher = launcher; } --- old/src/jdk.jpackage/windows/native/libjpackage/WinErrorHandling.cpp 2019-08-28 09:10:50.853632300 -0400 +++ new/src/jdk.jpackage/windows/native/libjpackage/WinErrorHandling.cpp 2019-08-28 09:10:48.840193500 -0400 @@ -38,13 +38,13 @@ HMODULE hmodule = NULL; if (c) { - GetModuleHandleEx( - GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - reinterpret_cast(c), - &hmodule); + GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + reinterpret_cast(c), &hmodule); if (!hmodule) { - LOG_WARNING(tstrings::any() << "GetModuleHandleEx() failed for " << c << " address."); + LOG_WARNING(tstrings::any() << "GetModuleHandleEx() failed for " + << c << " address."); } } if (hmodule || !c) { @@ -64,9 +64,9 @@ while (true) { DWORD res = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER - | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS - | (moduleHandle != NULL ? FORMAT_MESSAGE_FROM_HMODULE : 0), - moduleHandle, messageId, 0, (LPWSTR)&pMsg, 0, NULL); + | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS + | (moduleHandle != NULL ? FORMAT_MESSAGE_FROM_HMODULE : 0), + moduleHandle, messageId, 0, (LPWSTR)&pMsg, 0, NULL); if (res > 0) { // replace all non-printed chars with space for (DWORD i=0; i (error_description)" // in UNICODE is not defined, the string returned is utf8-encoded - static std::wstring getSysErrorMessage(DWORD errCode = GetLastError(), HMODULE moduleHandle = NULL); - + static std::wstring getSysErrorMessage(DWORD errCode = GetLastError(), + HMODULE moduleHandle = NULL); + // returns string "COM error 0x
(error_description)" // in UNICODE is not defined, the string returned is utf8-encoded static std::wstring getComErrorMessage(HRESULT hr); --- old/src/jdk.jpackage/windows/native/libjpackage/WinSysInfo.cpp 2019-08-28 09:11:28.016948500 -0400 +++ new/src/jdk.jpackage/windows/native/libjpackage/WinSysInfo.cpp 2019-08-28 09:11:26.050310600 -0400 @@ -105,10 +105,11 @@ // get module handle for the address of this function LPCWSTR address = reinterpret_cast(getCurrentModuleHandle); HMODULE hmodule = NULL; - if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - address, &hmodule)) + if (!GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS + | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, address, &hmodule)) { - JP_THROW(SysError(tstrings::any() << "GetModuleHandleExW failed", GetModuleHandleExW)); + JP_THROW(SysError(tstrings::any() << "GetModuleHandleExW failed", + GetModuleHandleExW)); } return hmodule; } --- old/src/jdk.jpackage/windows/native/libjpackage/WindowsRegistry.cpp 2019-08-28 09:11:42.576028800 -0400 +++ new/src/jdk.jpackage/windows/native/libjpackage/WindowsRegistry.cpp 2019-08-28 09:11:40.391986800 -0400 @@ -44,8 +44,10 @@ * Method: readDwordValue * Signature: (ILjava/lang/String;Ljava/lang/String;I)I */ - JNIEXPORT jint JNICALL Java_jdk_jpackage_internal_WindowsRegistry_readDwordValue( - JNIEnv *pEnv, jclass c, jint key, jstring jSubKey, jstring jValue, jint defaultValue) { + JNIEXPORT jint JNICALL + Java_jdk_jpackage_internal_WindowsRegistry_readDwordValue( + JNIEnv *pEnv, jclass c, jint key, jstring jSubKey, + jstring jValue, jint defaultValue) { jint jResult = defaultValue; if (key != jdk_jpackage_internal_WindowsRegistry_HKEY_LOCAL_MACHINE) { @@ -78,7 +80,8 @@ * Method: openRegistryKey * Signature: (ILjava/lang/String;)J */ - JNIEXPORT jlong JNICALL Java_jdk_jpackage_internal_WindowsRegistry_openRegistryKey( + JNIEXPORT jlong JNICALL + Java_jdk_jpackage_internal_WindowsRegistry_openRegistryKey( JNIEnv *pEnv, jclass c, jint key, jstring jSubKey) { if (key != jdk_jpackage_internal_WindowsRegistry_HKEY_LOCAL_MACHINE) { return 0; @@ -100,16 +103,18 @@ * Method: enumRegistryValue * Signature: (JI)Ljava/lang/String; */ - JNIEXPORT jstring JNICALL Java_jdk_jpackage_internal_WindowsRegistry_enumRegistryValue( + JNIEXPORT jstring JNICALL + Java_jdk_jpackage_internal_WindowsRegistry_enumRegistryValue( JNIEnv *pEnv, jclass c, jlong lKey, jint jIndex) { HKEY hKey = (HKEY)lKey; - TCHAR valueName[VALUE_NAME_SIZE] = {0}; // Max value name size per MSDN plus NULL + TCHAR valueName[VALUE_NAME_SIZE] = {0}; // Max size per MSDN plus NULL DWORD cchValueName = VALUE_NAME_SIZE; - LSTATUS status = RegEnumValue(hKey, (DWORD)jIndex, valueName, &cchValueName, - NULL, NULL, NULL, NULL); + LSTATUS status = RegEnumValue(hKey, (DWORD)jIndex, valueName, + &cchValueName, NULL, NULL, NULL, NULL); if (status == ERROR_SUCCESS) { size_t chLength = 0; - if (StringCchLength(valueName, VALUE_NAME_SIZE, &chLength) == S_OK) { + if (StringCchLength(valueName, VALUE_NAME_SIZE, &chLength) + == S_OK) { return GetJStringFromString(pEnv, valueName, (jsize)chLength); } } @@ -122,7 +127,8 @@ * Method: closeRegistryKey * Signature: (J)V */ - JNIEXPORT void JNICALL Java_jdk_jpackage_internal_WindowsRegistry_closeRegistryKey( + JNIEXPORT void JNICALL + Java_jdk_jpackage_internal_WindowsRegistry_closeRegistryKey( JNIEnv *pEnc, jclass c, jlong lKey) { HKEY hKey = (HKEY)lKey; RegCloseKey(hKey); @@ -133,8 +139,9 @@ * Method: comparePaths * Signature: (Ljava/lang/String;Ljava/lang/String;)Z */ - JNIEXPORT jboolean JNICALL Java_jdk_jpackage_internal_WindowsRegistry_comparePaths( - JNIEnv *pEnv, jclass c, jstring jPath1, jstring jPath2) { + JNIEXPORT jboolean JNICALL + Java_jdk_jpackage_internal_WindowsRegistry_comparePaths( + JNIEnv *pEnv, jclass c, jstring jPath1, jstring jPath2) { wstring path1 = GetStringFromJString(pEnv, jPath1); wstring path2 = GetStringFromJString(pEnv, jPath2); @@ -158,4 +165,4 @@ #ifdef __cplusplus } -#endif \ No newline at end of file +#endif --- old/src/jdk.jpackage/windows/native/libjpackage/jpackage.cpp 2019-08-28 09:12:01.052185800 -0400 +++ new/src/jdk.jpackage/windows/native/libjpackage/jpackage.cpp 2019-08-28 09:11:58.195330700 -0400 @@ -45,7 +45,8 @@ * Method: iconSwap * Signature: (Ljava/lang/String;Ljava/lang/String;)I */ - JNIEXPORT jint JNICALL Java_jdk_jpackage_internal_WindowsAppImageBuilder_iconSwap( + JNIEXPORT jint JNICALL + Java_jdk_jpackage_internal_WindowsAppImageBuilder_iconSwap( JNIEnv *pEnv, jclass c, jstring jIconTarget, jstring jLauncher) { wstring iconTarget = GetStringFromJString(pEnv, jIconTarget); wstring launcher = GetStringFromJString(pEnv, jLauncher); @@ -62,10 +63,13 @@ * Method: versionSwap * Signature: (Ljava/lang/String;Ljava/lang/String;)I */ - JNIEXPORT jint JNICALL Java_jdk_jpackage_internal_WindowsAppImageBuilder_versionSwap( - JNIEnv *pEnv, jclass c, jstring jExecutableProperties, jstring jLauncher) { + JNIEXPORT jint JNICALL + Java_jdk_jpackage_internal_WindowsAppImageBuilder_versionSwap( + JNIEnv *pEnv, jclass c, jstring jExecutableProperties, + jstring jLauncher) { - wstring executableProperties = GetStringFromJString(pEnv, jExecutableProperties); + wstring executableProperties = GetStringFromJString(pEnv, + jExecutableProperties); wstring launcher = GetStringFromJString(pEnv, jLauncher); VersionInfoSwap vs(executableProperties, launcher); @@ -101,7 +105,8 @@ return 1; } - BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { + BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, + LPVOID lpvReserved) { return TRUE; } --- old/src/jdk.jpackage/windows/native/libjpackage/tstrings.h 2019-08-28 09:12:21.962588400 -0400 +++ new/src/jdk.jpackage/windows/native/libjpackage/tstrings.h 2019-08-28 09:12:19.887748500 -0400 @@ -89,14 +89,18 @@ tstring unsafe_format(tstring::const_pointer format, ...); enum CompareType {CASE_SENSITIVE, IGNORE_CASE}; - bool equals(const tstring& a, const tstring& b, const CompareType ct=CASE_SENSITIVE); - bool startsWith(const tstring &str, const tstring &substr, const CompareType ct=CASE_SENSITIVE); - bool endsWith(const tstring &str, const tstring &substr, const CompareType ct=CASE_SENSITIVE); + bool equals(const tstring& a, const tstring& b, + const CompareType ct=CASE_SENSITIVE); + bool startsWith(const tstring &str, const tstring &substr, + const CompareType ct=CASE_SENSITIVE); + bool endsWith(const tstring &str, const tstring &substr, + const CompareType ct=CASE_SENSITIVE); enum SplitType {ST_ALL, ST_EXCEPT_EMPTY_STRING}; void split(tstring_array &strVector, const tstring &str, - const tstring &delimiter, const SplitType st = ST_ALL); - inline tstring_array split(const tstring &str, const tstring &delimiter, const SplitType st = ST_ALL) { + const tstring &delimiter, const SplitType st = ST_ALL); + inline tstring_array split(const tstring &str, const tstring &delimiter, + const SplitType st = ST_ALL) { tstring_array result; split(result, str, delimiter, st); return result; @@ -125,13 +129,16 @@ tstring toLower(const tstring& str); - tstring replace(const tstring &str, const tstring &search, const tstring &replace); + tstring replace(const tstring &str, const tstring &search, + const tstring &replace); } namespace tstrings { - inline std::string toUtf8(const std::string& utf8str) { return utf8str; } - + inline std::string toUtf8(const std::string& utf8str) { + return utf8str; + } + #ifdef TSTRINGS_WITH_WCHAR // conversion to Utf8 std::string toUtf8(const std::wstring& utf16str); @@ -139,10 +146,14 @@ // conversion to Utf16 std::wstring toUtf16(const std::string& utf8str); - inline std::wstring fromUtf8(const std::string& utf8str) { return toUtf16(utf8str); } + inline std::wstring fromUtf8(const std::string& utf8str) { + return toUtf16(utf8str); + } #else - inline std::string fromUtf8(const std::string& utf8str) { return utf8str; } + inline std::string fromUtf8(const std::string& utf8str) { + return utf8str; + } #endif } // namespace tstrings --- old/src/jdk.jpackage/windows/native/libwixhelper/libwixhelper.cpp 2019-08-28 09:12:40.142938500 -0400 +++ new/src/jdk.jpackage/windows/native/libwixhelper/libwixhelper.cpp 2019-08-28 09:12:36.866875500 -0400 @@ -58,12 +58,14 @@ TCHAR *szValue = NULL; DWORD cchSize = 0; - UINT result = MsiGetProperty(hInstall, TEXT("APPLICATIONFOLDER"), TEXT(""), &cchSize); + UINT result = MsiGetProperty(hInstall, TEXT("APPLICATIONFOLDER"), + TEXT(""), &cchSize); if (result == ERROR_MORE_DATA) { cchSize = cchSize + 1; // NULL termination szValue = new TCHAR[cchSize]; if (szValue) { - result = MsiGetProperty(hInstall, TEXT("APPLICATIONFOLDER"), szValue, &cchSize); + result = MsiGetProperty(hInstall, TEXT("APPLICATIONFOLDER"), + szValue, &cchSize); } else { return ERROR_INSTALL_FAILURE; } --- old/src/jdk.jpackage/windows/native/msiwrapper/Executor.cpp 2019-08-28 09:12:54.778020100 -0400 +++ new/src/jdk.jpackage/windows/native/msiwrapper/Executor.cpp 2019-08-28 09:12:52.562777500 -0400 @@ -61,7 +61,7 @@ int Executor::execAndWaitForExit() const { UniqueHandle h = startProcess(); - + const DWORD res = ::WaitForSingleObject(h.get(), INFINITE); if (WAIT_FAILED == res) { JP_THROW(SysError("WaitForSingleObject() failed", WaitForSingleObject)); @@ -80,7 +80,7 @@ LOG_TRACE(tstrings::any() << "Process with PID=" << processId << " terminated. Exit code=" << exitCode); - + return static_cast(exitCode); } --- old/src/jdk.jpackage/windows/native/msiwrapper/Executor.h 2019-08-28 09:13:08.479083900 -0400 +++ new/src/jdk.jpackage/windows/native/msiwrapper/Executor.h 2019-08-28 09:13:06.324242300 -0400 @@ -1,84 +1,84 @@ -/* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#ifndef EXECUTOR_H -#define EXECUTOR_H - -#include "tstrings.h" -#include "UniqueHandle.h" - - -class Executor { -public: - explicit Executor(const std::wstring& appPath=std::wstring()) { - app(appPath).visible(false); - } - - /** - * Returns command line configured with arg() calls so far. - */ - std::wstring args() const; - - /** - * Set path to application to execute. - */ - Executor& app(const std::wstring& v) { - appPath = v; - return *this; - } - - /** - * Adds another command line argument. - */ - Executor& arg(const std::wstring& v) { - argsArray.push_back(v); - return *this; - } - - /** - * Controls if application window should be visible. - */ - Executor& visible(bool v) { - theVisible = v; - return *this; - } - - /** - * Starts application process and blocks waiting when the started - * process terminates. - * Returns process exit code. - * Throws exception if process start failed. - */ - int execAndWaitForExit() const; - -private: - UniqueHandle startProcess() const; - - bool theVisible; - tstring_array argsArray; - std::wstring appPath; -}; - -#endif // #ifndef EXECUTOR_H +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#ifndef EXECUTOR_H +#define EXECUTOR_H + +#include "tstrings.h" +#include "UniqueHandle.h" + + +class Executor { +public: + explicit Executor(const std::wstring& appPath=std::wstring()) { + app(appPath).visible(false); + } + + /** + * Returns command line configured with arg() calls so far. + */ + std::wstring args() const; + + /** + * Set path to application to execute. + */ + Executor& app(const std::wstring& v) { + appPath = v; + return *this; + } + + /** + * Adds another command line argument. + */ + Executor& arg(const std::wstring& v) { + argsArray.push_back(v); + return *this; + } + + /** + * Controls if application window should be visible. + */ + Executor& visible(bool v) { + theVisible = v; + return *this; + } + + /** + * Starts application process and blocks waiting when the started + * process terminates. + * Returns process exit code. + * Throws exception if process start failed. + */ + int execAndWaitForExit() const; + +private: + UniqueHandle startProcess() const; + + bool theVisible; + tstring_array argsArray; + std::wstring appPath; +}; + +#endif // #ifndef EXECUTOR_H --- old/src/jdk.jpackage/windows/native/msiwrapper/MsiWrapper.cpp 2019-08-28 09:13:29.808694400 -0400 +++ new/src/jdk.jpackage/windows/native/msiwrapper/MsiWrapper.cpp 2019-08-28 09:13:26.610632900 -0400 @@ -1,41 +1,42 @@ -#include -#include - -#include "SysInfo.h" -#include "FileUtils.h" -#include "Executor.h" -#include "Resources.h" -#include "WinErrorHandling.h" - - -int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR lpCmdLine, int nShowCmd) -{ - JP_TRY; - - // Create temporary directory where to extract msi file. - const auto tempMsiDir = FileUtils::createTempDirectory(); - - // Schedule temporary directory for deletion. - FileUtils::Deleter cleaner; - cleaner.appendRecursiveDirectory(tempMsiDir); - - const auto msiPath = FileUtils::mkpath() << tempMsiDir << L"main.msi"; - - // Extract msi file. - Resource(L"msi", RT_RCDATA).saveToFile(msiPath); - - // Setup executor to run msiexec - Executor msiExecutor(SysInfo::getWIPath()); - msiExecutor.arg(L"/i").arg(msiPath); - const auto args = SysInfo::getCommandArgs(); - std::for_each(args.begin(), args.end(), [&msiExecutor] (const tstring& arg) { - msiExecutor.arg(arg); - }); - - // Install msi file. - return msiExecutor.execAndWaitForExit(); - - JP_CATCH_ALL; - - return -1; -} +#include +#include + +#include "SysInfo.h" +#include "FileUtils.h" +#include "Executor.h" +#include "Resources.h" +#include "WinErrorHandling.h" + + +int __stdcall WinMain(HINSTANCE, HINSTANCE, LPSTR lpCmdLine, int nShowCmd) +{ + JP_TRY; + + // Create temporary directory where to extract msi file. + const auto tempMsiDir = FileUtils::createTempDirectory(); + + // Schedule temporary directory for deletion. + FileUtils::Deleter cleaner; + cleaner.appendRecursiveDirectory(tempMsiDir); + + const auto msiPath = FileUtils::mkpath() << tempMsiDir << L"main.msi"; + + // Extract msi file. + Resource(L"msi", RT_RCDATA).saveToFile(msiPath); + + // Setup executor to run msiexec + Executor msiExecutor(SysInfo::getWIPath()); + msiExecutor.arg(L"/i").arg(msiPath); + const auto args = SysInfo::getCommandArgs(); + std::for_each(args.begin(), args.end(), + [&msiExecutor] (const tstring& arg) { + msiExecutor.arg(arg); + }); + + // Install msi file. + return msiExecutor.execAndWaitForExit(); + + JP_CATCH_ALL; + + return -1; +} --- old/src/jdk.jpackage/windows/native/msiwrapper/Resources.cpp 2019-08-28 09:13:49.253070100 -0400 +++ new/src/jdk.jpackage/windows/native/msiwrapper/Resources.cpp 2019-08-28 09:13:47.084628400 -0400 @@ -1,144 +1,149 @@ -/* - * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -#include "Resources.h" -#include "FileUtils.h" -#include "WinErrorHandling.h" - -#include - - -Resource::Resource(LPCTSTR name, LPCTSTR type, HINSTANCE module) { - init(name, type, module); -} - -Resource::Resource(UINT id, LPCTSTR type, HINSTANCE module) { - init(MAKEINTRESOURCE(id), type, module); -} - -void Resource::init(LPCTSTR name, LPCTSTR type, HINSTANCE module) { - if (IS_INTRESOURCE(name)) { - std::wostringstream printer; - printer << L"#" << reinterpret_cast(name); - nameStr = printer.str(); - namePtr = name; - } else { - nameStr = name; - namePtr = nameStr.c_str(); - } - if (IS_INTRESOURCE(type)) { - std::wostringstream printer; - printer << L"#" << reinterpret_cast(name); - typeStr = printer.str(); - typePtr = type; - } else { - typeStr = type; - typePtr = typeStr.c_str(); - } - instance = module; -} - -std::string Resource::getErrMsg(const std::string &descr) const { - return (tstrings::any() << descr << " (name='" << nameStr << "', type='" << typeStr << "')").str(); -} - -HRSRC Resource::findResource() const { - LPCTSTR id = namePtr; - // string resources are stored in blocks (stringtables) - // id of the resource is (stringId / 16 + 1) - if (typePtr == RT_STRING) { - id = MAKEINTRESOURCE(UINT(size_t(id) / 16 + 1)); - } - return FindResource(instance, id, typePtr); -} - -LPVOID Resource::getPtr(DWORD &size) const -{ - // LoadString returns the same result if value is zero-length or if if the value does not exists, - // so wee need to ensure the stringtable exists - HRSRC resInfo = findResource(); - if (resInfo == NULL) { - JP_THROW(SysError(getErrMsg("cannot find resource"), FindResource)); - } - - HGLOBAL res = LoadResource(instance, resInfo); - if (res == NULL) { - JP_THROW(SysError(getErrMsg("cannot load resource"), LoadResource)); - } - - LPVOID ptr = LockResource(res); - if (res == NULL) { - JP_THROW(SysError(getErrMsg("cannot lock resource"), LockResource)); - } - - if (typePtr == RT_STRING) { - // string resources are stored in stringtables and need special handling - // The simplest way (while we don't need handle resource locale) is LoadString - // But this adds dependency on user32.dll, so implement custom string extraction - - // number in the block (namePtr is an integer) - size_t num = size_t(namePtr) & 0xf; - LPWSTR strPtr = (LPWSTR)ptr; - for (size_t i = 0; i < num; i++) { - // 1st symbol contains string length - strPtr += DWORD(*strPtr) + 1; - } - // *strPtr contains string length, string value starts at strPtr+1 - size = DWORD(*strPtr) * sizeof(wchar_t); - ptr = strPtr+1; - } else { - size = SizeofResource(instance, resInfo); - } - - return ptr; -} - -bool Resource::available() const { - return NULL != findResource(); -} - -unsigned Resource::size() const { - DWORD size = 0; - getPtr(size); - return size; -} - -LPCVOID Resource::rawData() const { - DWORD size = 0; - return getPtr(size); -} - -void Resource::saveToFile(const std::wstring &filePath) const { - DWORD size = 0; - const char *resPtr = (const char *)getPtr(size); - - FileUtils::FileWriter(filePath).write(resPtr, size).finalize(); -} - -Resource::ByteArray Resource::binary() const { - DWORD size = 0; - LPBYTE resPtr = (LPBYTE)getPtr(size); - return ByteArray(resPtr, resPtr+size); -} +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +#include "Resources.h" +#include "FileUtils.h" +#include "WinErrorHandling.h" + +#include + + +Resource::Resource(LPCTSTR name, LPCTSTR type, HINSTANCE module) { + init(name, type, module); +} + +Resource::Resource(UINT id, LPCTSTR type, HINSTANCE module) { + init(MAKEINTRESOURCE(id), type, module); +} + +void Resource::init(LPCTSTR name, LPCTSTR type, HINSTANCE module) { + if (IS_INTRESOURCE(name)) { + std::wostringstream printer; + printer << L"#" << reinterpret_cast(name); + nameStr = printer.str(); + namePtr = name; + } else { + nameStr = name; + namePtr = nameStr.c_str(); + } + if (IS_INTRESOURCE(type)) { + std::wostringstream printer; + printer << L"#" << reinterpret_cast(name); + typeStr = printer.str(); + typePtr = type; + } else { + typeStr = type; + typePtr = typeStr.c_str(); + } + instance = module; +} + +std::string Resource::getErrMsg(const std::string &descr) const { + return (tstrings::any() << descr << " (name='" << nameStr << + "', type='" << typeStr << "')").str(); +} + +HRSRC Resource::findResource() const { + LPCTSTR id = namePtr; + // string resources are stored in blocks (stringtables) + // id of the resource is (stringId / 16 + 1) + if (typePtr == RT_STRING) { + id = MAKEINTRESOURCE(UINT(size_t(id) / 16 + 1)); + } + return FindResource(instance, id, typePtr); +} + +LPVOID Resource::getPtr(DWORD &size) const +{ + // LoadString returns the same result if value is zero-length or + // if if the value does not exists, + // so wee need to ensure the stringtable exists + HRSRC resInfo = findResource(); + if (resInfo == NULL) { + JP_THROW(SysError(getErrMsg("cannot find resource"), FindResource)); + } + + HGLOBAL res = LoadResource(instance, resInfo); + if (res == NULL) { + JP_THROW(SysError(getErrMsg("cannot load resource"), LoadResource)); + } + + LPVOID ptr = LockResource(res); + if (res == NULL) { + JP_THROW(SysError(getErrMsg("cannot lock resource"), LockResource)); + } + + if (typePtr == RT_STRING) { + // string resources are stored in stringtables and + // need special handling + // The simplest way (while we don't need handle resource locale) + // is LoadString + // But this adds dependency on user32.dll, + // so implement custom string extraction + + // number in the block (namePtr is an integer) + size_t num = size_t(namePtr) & 0xf; + LPWSTR strPtr = (LPWSTR)ptr; + for (size_t i = 0; i < num; i++) { + // 1st symbol contains string length + strPtr += DWORD(*strPtr) + 1; + } + // *strPtr contains string length, string value starts at strPtr+1 + size = DWORD(*strPtr) * sizeof(wchar_t); + ptr = strPtr+1; + } else { + size = SizeofResource(instance, resInfo); + } + + return ptr; +} + +bool Resource::available() const { + return NULL != findResource(); +} + +unsigned Resource::size() const { + DWORD size = 0; + getPtr(size); + return size; +} + +LPCVOID Resource::rawData() const { + DWORD size = 0; + return getPtr(size); +} + +void Resource::saveToFile(const std::wstring &filePath) const { + DWORD size = 0; + const char *resPtr = (const char *)getPtr(size); + + FileUtils::FileWriter(filePath).write(resPtr, size).finalize(); +} + +Resource::ByteArray Resource::binary() const { + DWORD size = 0; + LPBYTE resPtr = (LPBYTE)getPtr(size); + return ByteArray(resPtr, resPtr+size); +} --- old/src/jdk.jpackage/windows/native/msiwrapper/Resources.h 2019-08-28 09:14:36.499779400 -0400 +++ new/src/jdk.jpackage/windows/native/msiwrapper/Resources.h 2019-08-28 09:14:33.939330000 -0400 @@ -41,9 +41,12 @@ class Resource { public: - // name and type can be specified by string id, by integer id (RT_* constants or MAKEINTRESOURCE) - Resource(LPCWSTR name, LPCWSTR type, HINSTANCE module = SysInfo::getCurrentModuleHandle()); - Resource(UINT id, LPCWSTR type, HINSTANCE module = SysInfo::getCurrentModuleHandle()); + // name and type can be specified by string id, + // by integer id (RT_* constants or MAKEINTRESOURCE) + Resource(LPCWSTR name, LPCWSTR type, + HINSTANCE module = SysInfo::getCurrentModuleHandle()); + Resource(UINT id, LPCWSTR type, + HINSTANCE module = SysInfo::getCurrentModuleHandle()); bool available() const; @@ -61,9 +64,9 @@ private: std::wstring nameStr; - LPCWSTR namePtr; // can be integer (MAKEINTRESOURCE) value or point to nameStr.c_str() + LPCWSTR namePtr; // can be integer value or point to nameStr.c_str() std::wstring typeStr; - LPCWSTR typePtr; // can be integer (MAKEINTRESOURCE) value or point to nameStr.c_str() + LPCWSTR typePtr; // can be integer value or point to nameStr.c_str() HINSTANCE instance; void init(LPCWSTR name, LPCWSTR type, HINSTANCE module); --- old/test/jdk/tools/jpackage/linux/base/MaintainerBase.java 2019-08-28 09:14:51.765274900 -0400 +++ new/test/jdk/tools/jpackage/linux/base/MaintainerBase.java 2019-08-28 09:14:49.424229800 -0400 @@ -62,7 +62,7 @@ } } } - + if (!maintainerFound) { throw new AssertionError("Maintainer field not found"); } --- old/test/jdk/tools/jpackage/share/AddLauncherBase.java 2019-08-28 09:15:13.643896200 -0400 +++ new/test/jdk/tools/jpackage/share/AddLauncherBase.java 2019-08-28 09:15:11.115647500 -0400 @@ -166,7 +166,7 @@ out.println("main-class Hello"); } - + } } --- old/test/jdk/tools/jpackage/share/ResourceTest.java 2019-08-28 09:15:27.704767000 -0400 +++ new/test/jdk/tools/jpackage/share/ResourceTest.java 2019-08-28 09:15:25.628927000 -0400 @@ -38,7 +38,7 @@ private static final String OUTPUT = "output"; private static final String app = JPackagePath.getApp("icon"); private static final String appOutput = JPackagePath.getAppOutputFile(); - private static final String resourceDir = + private static final String resourceDir = JPackagePath.getTestSrcRoot() + File.separator + "resources"; private static final String[] CMD = { --- old/test/jdk/tools/jpackage/windows/exe/FileAssociationsInstallDirTest.java 2019-08-28 09:15:41.356029600 -0400 +++ new/test/jdk/tools/jpackage/windows/exe/FileAssociationsInstallDirTest.java 2019-08-28 09:15:39.233388700 -0400 @@ -24,12 +24,12 @@ /* * Test both --file-associations and --install-dir parameters. * Output of the test should be FileAssociationsInstallDirTest-1.0.exe installer. - * For the expected behavior and suggested testing see descriptions of + * For the expected behavior and suggested testing see descriptions of * FileAssociationsTest and InstallDirTest tests. - * Note: file association suffix is ".jptest3" and not ".jptest1" as in + * Note: file association suffix is ".jptest3" and not ".jptest1" as in * FileAssociationsTest test. */ - + /* * @test * @summary jpackage create installer test --- old/test/jdk/tools/jpackage/windows/exe/FileAssociationsTest.java 2019-08-28 09:16:27.049709600 -0400 +++ new/test/jdk/tools/jpackage/windows/exe/FileAssociationsTest.java 2019-08-28 09:16:24.864667500 -0400 @@ -24,15 +24,15 @@ /* * Test --file-associations parameter. * Output of the test should be FileAssociationsTest-1.0.exe installer. - * The output installer should provide the same functionality as the default - * installer (see description of the default installer in Test.java) plus + * The output installer should provide the same functionality as the default + * installer (see description of the default installer in Test.java) plus * configure file associations. - * After installation files with ".jptest1" suffix should be associated with + * After installation files with ".jptest1" suffix should be associated with * the test app. * - * Suggested test scenario is to create empty file with ".jptest1" suffix, - * double click on it and make sure that test application was launched in - * response to double click event with the path to test .jptest1 file + * Suggested test scenario is to create empty file with ".jptest1" suffix, + * double click on it and make sure that test application was launched in + * response to double click event with the path to test .jptest1 file * on the commend line. */ --- old/test/jdk/tools/jpackage/windows/exe/InstallDirTest.java 2019-08-28 09:16:43.588027800 -0400 +++ new/test/jdk/tools/jpackage/windows/exe/InstallDirTest.java 2019-08-28 09:16:41.449786600 -0400 @@ -24,9 +24,9 @@ /* * Test --install-dir parameter. * Output of the test should be InstallDirTest-1.0.exe installer. - * The output installer should provide the same functionality as the default - * installer (see description of the default installer in Test.java) but - * install test app in %ProgramFiles%\TestVendor\InstallDirTest instead of + * The output installer should provide the same functionality as the default + * installer (see description of the default installer in Test.java) but + * install test app in %ProgramFiles%\TestVendor\InstallDirTest instead of * %ProgramFiles%\InstallDirTest directory. */ --- old/test/jdk/tools/jpackage/windows/exe/LicenseTest.java 2019-08-28 09:16:58.819921200 -0400 +++ new/test/jdk/tools/jpackage/windows/exe/LicenseTest.java 2019-08-28 09:16:56.682680100 -0400 @@ -24,9 +24,9 @@ /* * Test --license-file parameter. * Output of the test should be LicenseTest-1.0.exe installer. - * The output installer should provide the same functionality as the default - * installer (see description of the default installer in Test.java) plus - * should display license text matching contents of + * The output installer should provide the same functionality as the default + * installer (see description of the default installer in Test.java) plus + * should display license text matching contents of * test/jdk/tools/jpackage/resources/license.txt file from OpenJDK repo. */ --- old/test/jdk/tools/jpackage/windows/exe/RuntimeTest.java 2019-08-28 09:17:15.564043600 -0400 +++ new/test/jdk/tools/jpackage/windows/exe/RuntimeTest.java 2019-08-28 09:17:13.598405800 -0400 @@ -27,7 +27,7 @@ * Test --runtime-image parameter. * Output of the test should be RuntimeTest-1.0.exe installer. * The installer should install Java Runtime without an application. - * Installation directory should not have "app" subfolder and should not have + * Installation directory should not have "app" subfolder and should not have * an application launcher. * No shortcuts should be created in Windows Menu. * Java runtime should be installed in %ProgramFiles%\RuntimeTest directory. --- old/test/jdk/tools/jpackage/windows/exe/Test.java 2019-08-28 09:17:58.560871900 -0400 +++ new/test/jdk/tools/jpackage/windows/exe/Test.java 2019-08-28 09:17:56.595234100 -0400 @@ -24,7 +24,7 @@ /* * Test defaults for exe installer. * Output of the test should be Test-1.0.exe installer. - * The installer should not have license text. It should not have an option + * The installer should not have license text. It should not have an option * to change the default installation directory. * Test application should be installed in %ProgramFiles%\Test directory. * Installer should install test app for all users (machine wide). --- old/test/jdk/tools/jpackage/windows/exe/WinDirChooserTest.java 2019-08-28 09:18:13.433958400 -0400 +++ new/test/jdk/tools/jpackage/windows/exe/WinDirChooserTest.java 2019-08-28 09:18:11.076312900 -0400 @@ -24,8 +24,8 @@ /* * Test --win-dir-chooser parameter. * Output of the test should be WinDirChooserTest-1.0.exe installer. - * The output installer should provide the same functionality as the default - * installer (see description of the default installer in Test.java) plus + * The output installer should provide the same functionality as the default + * installer (see description of the default installer in Test.java) plus * provide an option for user to change the default installation directory. */ --- old/test/jdk/tools/jpackage/windows/exe/WinMenuGroupTest.java 2019-08-28 09:18:35.286379600 -0400 +++ new/test/jdk/tools/jpackage/windows/exe/WinMenuGroupTest.java 2019-08-28 09:18:32.601127800 -0400 @@ -24,9 +24,9 @@ /* * Test --win-menu and --win-menu-group parameters. * Output of the test should be WinMenuGroupTest-1.0.exe installer. - * The output installer should provide the same functionality as the default - * installer (see description of the default installer in Test.java) plus - * it should create a shortcut for application launcher in Windows Menu in + * The output installer should provide the same functionality as the default + * installer (see description of the default installer in Test.java) plus + * it should create a shortcut for application launcher in Windows Menu in * "C:\ProgramData\Microsoft\Windows\Start Menu\Programs\WinMenuGroupTest_MenuGroup" folder. */ --- old/test/jdk/tools/jpackage/windows/exe/WinMenuTest.java 2019-08-28 09:18:53.401130700 -0400 +++ new/test/jdk/tools/jpackage/windows/exe/WinMenuTest.java 2019-08-28 09:18:51.045485400 -0400 @@ -24,7 +24,7 @@ /* * Test --win-menu parameter. * Output of the test should be WinMenuTest-1.0.exe installer. - * The output installer should provide the same functionality as the default + * The output installer should provide the same functionality as the default * installer (see description of the default installer in Test.java). */ --- old/test/jdk/tools/jpackage/windows/exe/WinPerUserInstallTest.java 2019-08-28 09:19:18.523015500 -0400 +++ new/test/jdk/tools/jpackage/windows/exe/WinPerUserInstallTest.java 2019-08-28 09:19:16.445175300 -0400 @@ -24,12 +24,12 @@ /* * Test --win-per-user-install, --win-menu, --win-menu-group parameters. * Output of the test should be WinPerUserInstallTest-1.0.exe installer. - * The output installer should provide the same functionality as the default installer - * (see description of the default installer in Test.java) plus it should - * create application menu in Windows Menu and installation should be per + * The output installer should provide the same functionality as the default installer + * (see description of the default installer in Test.java) plus it should + * create application menu in Windows Menu and installation should be per * user and not machine wide. */ - + /* * @test * @summary jpackage create installer test --- old/test/jdk/tools/jpackage/windows/exe/WinShortcutTest.java 2019-08-28 09:19:32.495285000 -0400 +++ new/test/jdk/tools/jpackage/windows/exe/WinShortcutTest.java 2019-08-28 09:19:30.495446300 -0400 @@ -24,8 +24,8 @@ /* * Test --win-shortcut parameter. * Output of the test should be WinShortcutTest-1.0.exe installer. - * The output installer should provide the same functionality as the default installer - * (see description of the default installer in Test.java) plus install + * The output installer should provide the same functionality as the default installer + * (see description of the default installer in Test.java) plus install * application shortcut on the desktop. */ --- old/test/jdk/tools/jpackage/windows/exe/WinUpgradeUUIDTest.java 2019-08-28 09:19:47.176568700 -0400 +++ new/test/jdk/tools/jpackage/windows/exe/WinUpgradeUUIDTest.java 2019-08-28 09:19:44.930125500 -0400 @@ -23,12 +23,12 @@ /* * Test both --win-upgrade-uuid and --app-version parameters. - * Output of the test should be WinUpgradeUUIDTest-1.0.exe + * Output of the test should be WinUpgradeUUIDTest-1.0.exe * and WinUpgradeUUIDTest-2.0.exe installers. - * Both output installers should provide the same functionality as the default - * installer (see description of the default installer in Test.java) but have + * Both output installers should provide the same functionality as the default + * installer (see description of the default installer in Test.java) but have * the same product code and different versions. - * Running WinUpgradeUUIDTest-2.0.exe installer should automatically + * Running WinUpgradeUUIDTest-2.0.exe installer should automatically * uninstall older version of the test application previously installed with * WinUpgradeUUIDTest-1.0.exe installer. */