8221333: Replace Inno Setup with custom MSI wrapper for .exe bundler (missed files)
Submitted-by: asemenyuk
Reviewed-by: herrick, almatvee
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java.html Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,240 @@
+<?xml version="1.0"?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head><meta charset="utf-8">
+<meta http-equiv="cache-control" content="no-cache" />
+<meta http-equiv="Pragma" content="no-cache" />
+<meta http-equiv="Expires" content="-1" />
+<!--
+ Note to customizers: the body of the webrev is IDed as SUNWwebrev
+ to allow easy overriding by users of webrev via the userContent.css
+ mechanism available in some browsers.
+
+ For example, to have all "removed" information be red instead of
+ brown, set a rule in your userContent.css file like:
+
+ body#SUNWwebrev span.removed { color: red ! important; }
+-->
+<style type="text/css" media="screen">
+body {
+ background-color: #eeeeee;
+}
+hr {
+ border: none 0;
+ border-top: 1px solid #aaa;
+ height: 1px;
+}
+div.summary {
+ font-size: .8em;
+ border-bottom: 1px solid #aaa;
+ padding-left: 1em;
+ padding-right: 1em;
+}
+div.summary h2 {
+ margin-bottom: 0.3em;
+}
+div.summary table th {
+ text-align: right;
+ vertical-align: top;
+ white-space: nowrap;
+}
+span.lineschanged {
+ font-size: 0.7em;
+}
+span.oldmarker {
+ color: red;
+ font-size: large;
+ font-weight: bold;
+}
+span.newmarker {
+ color: green;
+ font-size: large;
+ font-weight: bold;
+}
+span.removed {
+ color: brown;
+}
+span.changed {
+ color: blue;
+}
+span.new {
+ color: blue;
+ font-weight: bold;
+}
+a.print { font-size: x-small; }
+
+</style>
+
+<style type="text/css" media="print">
+pre { font-size: 0.8em; font-family: courier, monospace; }
+span.removed { color: #444; font-style: italic }
+span.changed { font-weight: bold; }
+span.new { font-weight: bold; }
+span.newmarker { font-size: 1.2em; font-weight: bold; }
+span.oldmarker { font-size: 1.2em; font-weight: bold; }
+a.print {display: none}
+hr { border: none 0; border-top: 1px solid #aaa; height: 1px; }
+</style>
+
+<title>New src/jdk.jpackage/windows/classes/jdk/jpackage/internal/WinExeBundler.java</title>
+<body id="SUNWwebrev">
+<pre>
+ 1 /*
+ 2 * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ 4 *
+ 5 * This code is free software; you can redistribute it and/or modify it
+ 6 * under the terms of the GNU General Public License version 2 only, as
+ 7 * published by the Free Software Foundation. Oracle designates this
+ 8 * particular file as subject to the "Classpath" exception as provided
+ 9 * by Oracle in the LICENSE file that accompanied this code.
+ 10 *
+ 11 * This code is distributed in the hope that it will be useful, but WITHOUT
+ 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ 14 * version 2 for more details (a copy is included in the LICENSE file that
+ 15 * accompanied this code).
+ 16 *
+ 17 * You should have received a copy of the GNU General Public License version
+ 18 * 2 along with this work; if not, write to the Free Software Foundation,
+ 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ 20 *
+ 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ 22 * or visit www.oracle.com if you need additional information or have any
+ 23 * questions.
+ 24 */
+ 25 package jdk.jpackage.internal;
+ 26
+ 27 import java.io.*;
+ 28 import java.nio.file.Files;
+ 29 import java.nio.file.Path;
+ 30 import java.nio.file.Paths;
+ 31 import java.text.MessageFormat;
+ 32 import java.util.*;
+ 33
+ 34 public class WinExeBundler extends AbstractBundler {
+ 35
+ 36 static {
+ 37 System.loadLibrary("jpackage");
+ 38 }
+ 39
+ 40 private static final ResourceBundle I18N = ResourceBundle.getBundle(
+ 41 "jdk.jpackage.internal.resources.WinResources");
+ 42
+ 43 public static final BundlerParamInfo<WinAppBundler> APP_BUNDLER
+ 44 = new WindowsBundlerParam<>(
+ 45 "win.app.bundler",
+ 46 WinAppBundler.class,
+ 47 params -> new WinAppBundler(),
+ 48 null);
+ 49
+ 50 public static final BundlerParamInfo<File> EXE_IMAGE_DIR
+ 51 = new WindowsBundlerParam<>(
+ 52 "win.exe.imageDir",
+ 53 File.class,
+ 54 params -> {
+ 55 File imagesRoot = IMAGES_ROOT.fetchFrom(params);
+ 56 if (!imagesRoot.exists()) {
+ 57 imagesRoot.mkdirs();
+ 58 }
+ 59 return new File(imagesRoot, "win-exe.image");
+ 60 },
+ 61 (s, p) -> null);
+ 62
+ 63 private final static String EXE_WRAPPER_NAME = "msiwrapper.exe";
+ 64
+ 65 @Override
+ 66 public String getName() {
+ 67 return getString("exe.bundler.name");
+ 68 }
+ 69
+ 70 @Override
+ 71 public String getDescription() {
+ 72 return getString("exe.bundler.description");
+ 73 }
+ 74
+ 75 @Override
+ 76 public String getID() {
+ 77 return "exe";
+ 78 }
+ 79
+ 80 @Override
+ 81 public String getBundleType() {
+ 82 return "INSTALLER";
+ 83 }
+ 84
+ 85 @Override
+ 86 public Collection<BundlerParamInfo<?>> getBundleParameters() {
+ 87 return new WinMsiBundler().getBundleParameters();
+ 88 }
+ 89
+ 90 @Override
+ 91 public File execute(Map<String, ? super Object> params,
+ 92 File outputParentDir) throws PackagerException {
+ 93 return bundle(params, outputParentDir);
+ 94 }
+ 95
+ 96 @Override
+ 97 public boolean supported(boolean platformInstaller) {
+ 98 return (Platform.getPlatform() == Platform.WINDOWS);
+ 99 }
+ 100
+ 101 @Override
+ 102 public boolean validate(Map<String, ? super Object> params)
+ 103 throws UnsupportedPlatformException, ConfigException {
+ 104 return new WinMsiBundler().validate(params);
+ 105 }
+ 106
+ 107 public File bundle(Map<String, ? super Object> params, File outdir)
+ 108 throws PackagerException {
+ 109
+ 110 File exeImageDir = EXE_IMAGE_DIR.fetchFrom(params);
+ 111
+ 112 // Write msi to temporary directory.
+ 113 File msi = new WinMsiBundler().bundle(params, exeImageDir);
+ 114
+ 115 try {
+ 116 return buildEXE(msi, outdir);
+ 117 } catch (IOException ex) {
+ 118 Log.verbose(ex);
+ 119 throw new PackagerException(ex);
+ 120 }
+ 121 }
+ 122
+ 123 private File buildEXE(File msi, File outdir)
+ 124 throws IOException {
+ 125
+ 126 Log.verbose(MessageFormat.format(
+ 127 getString("message.outputting-to-location"),
+ 128 outdir.getAbsolutePath()));
+ 129
+ 130 // Copy template msi wrapper next to msi file
+ 131 String exePath = msi.getAbsolutePath();
+ 132 exePath = exePath.substring(0, exePath.lastIndexOf('.')) + ".exe";
+ 133 try (InputStream is = getResourceAsStream(EXE_WRAPPER_NAME)) {
+ 134 Files.copy(is, Path.of(exePath));
+ 135 }
+ 136 // Embed msi in msi wrapper exe.
+ 137 embedMSI(exePath, msi.getAbsolutePath());
+ 138
+ 139 Path dstExePath = Paths.get(outdir.getAbsolutePath(), Path.of(exePath).getFileName().toString());
+ 140 Files.deleteIfExists(dstExePath);
+ 141
+ 142 Files.copy(Path.of(exePath), dstExePath);
+ 143
+ 144 Log.verbose(MessageFormat.format(
+ 145 getString("message.output-location"),
+ 146 outdir.getAbsolutePath()));
+ 147
+ 148 return dstExePath.toFile();
+ 149 }
+ 150
+ 151 private static String getString(String key)
+ 152 throws MissingResourceException {
+ 153 return I18N.getString(key);
+ 154 }
+ 155
+ 156 private static native int embedMSI(String exePath, String msiPath);
+ 157 }
+</pre></body></html>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/libjpackage/ErrorHandling.cpp Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,141 @@
+/*
+ * 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 <algorithm>
+
+#include "ErrorHandling.h"
+#include "Log.h"
+
+
+namespace {
+
+tstring getFilename(const SourceCodePos& pos) {
+ const std::string buf(pos.file);
+ const std::string::size_type idx = buf.find_last_of("\\/");
+ if (idx == std::string::npos) {
+ return tstrings::fromUtf8(buf);
+ }
+ return tstrings::fromUtf8(buf.substr(idx + 1));
+}
+
+void reportError(const SourceCodePos& pos, const tstring& msg) {
+ Logger::defaultLogger().log(Logger::LOG_ERROR, getFilename(pos).c_str(),
+ pos.lno, tstrings::fromUtf8(pos.func).c_str(), msg);
+}
+
+} // namespace
+
+void reportError(const SourceCodePos& pos, const std::exception& e) {
+ reportError(pos, (tstrings::any() << "Exception with message \'"
+ << e.what() << "\' caught").tstr());
+}
+
+
+void reportUnknownError(const SourceCodePos& pos) {
+ reportError(pos, _T("Unknown exception caught"));
+}
+
+
+std::string makeMessage(const std::exception& e, const SourceCodePos& pos) {
+ std::ostringstream printer;
+ printer << getFilename(pos) << "(" << pos.lno << ") at "
+ << pos.func << "(): "
+ << e.what();
+ return printer.str();
+}
+
+
+namespace {
+
+bool isNotSpace(int chr) {
+ return isspace(chr) == 0;
+}
+
+
+enum TrimMode {
+ TrimLeading = 0x10,
+ TrimTrailing = 0x20,
+ TrimBoth = TrimLeading | TrimTrailing
+};
+
+// Returns position of the last printed character in the given string.
+// Returns std::string::npos if nothing was printed.
+size_t printWithoutWhitespaces(std::ostream& out, const std::string& str,
+ TrimMode mode) {
+ std::string::const_reverse_iterator it = str.rbegin();
+ std::string::const_reverse_iterator end = str.rend();
+
+ if (mode & TrimLeading) {
+ // skip leading whitespace
+ std::string::const_iterator entry = std::find_if(str.begin(),
+ str.end(), isNotSpace);
+ end = std::string::const_reverse_iterator(entry);
+ }
+
+ if (mode & TrimTrailing) {
+ // skip trailing whitespace
+ it = std::find_if(it, end, isNotSpace);
+ }
+
+ if (it == end) {
+ return std::string::npos;
+ }
+
+ const size_t pos = str.rend() - end;
+ const size_t len = end - it;
+ out.write(str.c_str() + pos, len);
+ return pos + len - 1;
+}
+
+} // namespace
+
+std::string joinErrorMessages(const std::string& a, const std::string& b) {
+ const std::string endPhraseChars(";.,:!?");
+ const std::string space(" ");
+ const std::string dotAndSpace(". ");
+
+ std::ostringstream printer;
+ printer.exceptions(std::ios::failbit | std::ios::badbit);
+
+ size_t idx = printWithoutWhitespaces(printer, a, TrimTrailing);
+ size_t extra = 0;
+ if (idx < a.size() && endPhraseChars.find(a[idx]) == std::string::npos) {
+ printer << dotAndSpace;
+ extra = dotAndSpace.size();
+ } else if (idx != std::string::npos) {
+ printer << space;
+ extra = space.size();
+ }
+
+ idx = printWithoutWhitespaces(printer, b, TrimBoth);
+
+ const std::string str = printer.str();
+
+ if (std::string::npos == idx && extra) {
+ // Nothing printed from the 'b' message. Backout delimiter string.
+ return str.substr(0, str.size() - extra);
+ }
+ return str;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/libjpackage/ErrorHandling.h Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,151 @@
+/*
+ * 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 ErrorHandling_h
+#define ErrorHandling_h
+
+
+#include <stdexcept>
+
+#include "SourceCodePos.h"
+#include "tstrings.h"
+
+
+//
+// Exception handling helpers. Allow transparent exception logging.
+// Use as follows:
+//
+// void foo () {
+// JP_TRY;
+//
+// if (!do_something()) {
+// JP_THROW("do_something() failed");
+// }
+//
+// JP_CATCH_ALL;
+// }
+//
+
+
+// Logs std::exception caught at 'pos'.
+void reportError(const SourceCodePos& pos, const std::exception& e);
+// Logs unknown exception caught at 'pos'.
+// Assumed to be called from catch (...) {}
+void reportUnknownError(const SourceCodePos& pos);
+
+std::string makeMessage(const std::exception& e, const SourceCodePos& pos);
+
+std::string joinErrorMessages(const std::string& a, const std::string& b);
+
+
+template <class Base>
+class JpError: public Base {
+public:
+ JpError(const Base& e, const SourceCodePos& pos):
+ Base(e), msg(::makeMessage(e, pos)) {
+ }
+
+ ~JpError() throw() {
+ }
+
+ // override Base::what()
+ const char* what() const throw() {
+ return msg.c_str();
+ }
+private:
+ // Assert Base is derived from std::exception
+ enum { isDerivedFromStdException =
+ sizeof(static_cast<std::exception*>((Base*)0)) };
+
+ std::string msg;
+};
+
+template <class T>
+inline JpError<T> makeException(const T& obj, const SourceCodePos& p) {
+ return JpError<T>(obj, p);
+}
+
+inline JpError<std::runtime_error> makeException(
+ const std::string& msg, const SourceCodePos& p) {
+ return JpError<std::runtime_error>(std::runtime_error(msg), p);
+}
+
+inline JpError<std::runtime_error> makeException(
+ const tstrings::any& msg, const SourceCodePos& p) {
+ return makeException(msg.str(), p);
+}
+
+inline JpError<std::runtime_error> makeException(
+ std::string::const_pointer msg, const SourceCodePos& p) {
+ return makeException(std::string(msg), p);
+}
+
+
+#define JP_REPORT_ERROR(e) reportError(JP_SOURCE_CODE_POS, e)
+#define JP_REPORT_UNKNOWN_ERROR reportUnknownError(JP_SOURCE_CODE_POS)
+
+// Redefine locally in cpp file(s) if need more handling than just reporting
+#define JP_HANDLE_ERROR(e) JP_REPORT_ERROR(e)
+#define JP_HANDLE_UNKNOWN_ERROR JP_REPORT_UNKNOWN_ERROR
+
+
+#define JP_TRY \
+ try \
+ { \
+ do {} while(0)
+
+#define JP_DEFAULT_CATCH_EXCEPTIONS \
+ JP_CATCH_STD_EXCEPTION \
+ JP_CATCH_UNKNOWN_EXCEPTION
+
+#define JP_CATCH_EXCEPTIONS \
+ JP_DEFAULT_CATCH_EXCEPTIONS
+
+#define JP_CATCH_ALL \
+ } \
+ JP_CATCH_EXCEPTIONS \
+ do {} while(0)
+
+#define JP_CATCH_STD_EXCEPTION \
+ catch (const std::exception& e) \
+ { \
+ JP_HANDLE_ERROR(e); \
+ }
+
+#define JP_CATCH_UNKNOWN_EXCEPTION \
+ catch (...) \
+ { \
+ JP_HANDLE_UNKNOWN_ERROR; \
+ }
+
+
+#define JP_THROW(e) throw makeException((e), JP_SOURCE_CODE_POS)
+
+#define JP_NO_THROW(expr) \
+ JP_TRY; \
+ expr; \
+ JP_CATCH_ALL
+
+#endif // #ifndef ErrorHandling_h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/libjpackage/FileUtils.cpp Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,702 @@
+/*
+ * 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 <memory>
+#include <algorithm>
+#include <shlwapi.h>
+
+#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<DeleteFilesCallback> callback;
+ if (recursive) {
+ callback = std::unique_ptr<DeleteFilesCallback>(
+ new DeleteAllCallback(failfast));
+ } else {
+ callback = std::unique_ptr<DeleteFilesCallback>(
+ 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<HANDLE, FindFileDeleter> 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<const char*>(buf), bytes);
+ return *this;
+}
+
+void FileWriter::finalize() {
+ tmp.close();
+
+ FileUtils::moveFile(tmpFile, dstPath, false);
+
+ // cancel file deletion
+ cleaner.cancel();
+}
+
+} // namespace FileUtils
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/libjpackage/FileUtils.h Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,378 @@
+/*
+ * 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 FILEUTILS_H
+#define FILEUTILS_H
+
+
+#include <fstream>
+#include "SysInfo.h"
+
+
+namespace FileUtils {
+
+ // Returns 'true' if the given character is a path separator.
+ bool isDirSeparator(const tstring::value_type c);
+
+ // checks if the file or directory exists
+ bool isFileExists(const tstring &filePath);
+
+ // checks is the specified file is a directory
+ // 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 "..".
+ 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).
+ tstring dirname(const tstring &path);
+
+ // returns basename part of the path
+ // if the path ends with slash/backslash, returns empty string.
+ tstring basename(const tstring &path);
+
+ /**
+ * Translates forward slashes to back slashes and returns lower case version
+ * of the given string.
+ */
+ tstring normalizePath(tstring v);
+
+ // Returns suffix of the path. If the given path has a suffix the first
+ // character of the return value is '.'.
+ // Otherwise return value if empty string.
+ tstring suffix(const tstring &path);
+
+ // combines two strings into a path
+ tstring combinePath(const tstring& parent, const tstring& child);
+
+ // 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
+ // path is constructed as <prefix><random number><suffix>.
+ // 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());
+
+ // Creates a directory with unique name in the specified base directory, throws an exception if operation fails
+ // path is constructed as <prefix><random number><suffix>
+ // 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());
+
+ // 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
+ // created file is unique.
+ tstring createUniqueFile(const tstring &prototype);
+
+ // Creates directory and subdirectories if don't exist.
+ // Currently supports only "standard" path like "c:\bla-bla"
+ // If 'createdDirs' parameter is not NULL, the given array is appended with
+ // 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);
+
+ // Throws exception if fails to delete specified 'path'.
+ // Exits normally if 'path' doesn't exist or it has been deleted.
+ // Attempts to strip R/O attribute if delete fails and retry delete.
+ void deleteFile(const tstring &path);
+ // Returns 'false' if fails to delete specified 'path'.
+ // Returns 'true' if 'path' doesn't exist or it has been deleted.
+ // Attempts to strip R/O attribute if delete fails and retry delete.
+ bool deleteFile(const tstring &path, const std::nothrow_t &) throw();
+
+ // Like deleteFile(), but applies to directories.
+ void deleteDirectory(const tstring &path);
+ bool deleteDirectory(const tstring &path, const std::nothrow_t &) throw();
+
+ // Deletes all files (not subdirectories) from the specified directory.
+ // Exits normally if all files in 'dirPath' have been deleted or if
+ // 'dirPath' doesn't exist.
+ // Throws exception if 'dirPath' references existing file system object
+ // which is not a directory or when the first failure of file delete
+ // occurs.
+ void deleteFilesInDirectory(const tstring &dirPath);
+ // Deletes all files (not subdirectories) from the specified directory.
+ // Returns 'true' normally if all files in 'dirPath' have been deleted or
+ // if 'dirPath' doesn't exist.
+ // Returns 'false' if 'dirPath' references existing file system object
+ // which is not a directory or if failed to delete one ore more files in
+ // '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();
+ // Like deleteFilesInDirectory, but deletes subdirectories as well
+ void deleteDirectoryRecursive(const tstring &dirPath);
+ bool deleteDirectoryRecursive(const tstring &dirPath, const std::nothrow_t &) throw();
+
+ class DirectoryCallback {
+ public:
+ virtual ~DirectoryCallback() {};
+
+ virtual bool onFile(const tstring& path) {
+ return true;
+ }
+ virtual bool onDirectory(const tstring& path) {
+ return true;
+ }
+ };
+
+ // Calls the given callback for every file and subdirectory of
+ // the given directory.
+ void iterateDirectory(const tstring &dirPath, DirectoryCallback& callback);
+
+ /**
+ * Replace file suffix, example replaceSuffix("file/path.txt", ".csv")
+ * @param path file path to replace suffix
+ * @param suffix new suffix for path
+ * @return return file path with new suffix
+ */
+ tstring replaceSuffix(const tstring& path, const tstring& suffix=tstring());
+
+ class DirectoryIterator: DirectoryCallback {
+ public:
+ DirectoryIterator(const tstring& root=tstring()): root(root) {
+ recurse().withFiles().withFolders();
+ }
+
+ DirectoryIterator& recurse(bool v=true) {
+ theRecurse = v;
+ return *this;
+ }
+
+ DirectoryIterator& withFiles(bool v=true) {
+ theWithFiles = v;
+ return *this;
+ }
+
+ DirectoryIterator& withFolders(bool v=true) {
+ theWithFolders = v;
+ return *this;
+ }
+
+ tstring_array findItems() {
+ tstring_array reply;
+ findItems(reply);
+ return reply;
+ }
+
+ DirectoryIterator& findItems(tstring_array& v);
+
+ private:
+ virtual bool onFile(const tstring& path);
+ virtual bool onDirectory(const tstring& path);
+
+ private:
+ bool theRecurse;
+ bool theWithFiles;
+ bool theWithFolders;
+ tstring root;
+ 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.
+ inline tstring_array listAllContents(const tstring& basedir) {
+ return DirectoryIterator(basedir).findItems();
+ }
+
+ // Helper to construct path from multiple components.
+ //
+ // Sample usage:
+ // Construct "c:\Program Files\Java" string from three components
+ //
+ // tstring path = FileUtils::mkpath() << _T("c:")
+ // << _T("Program Files")
+ // << _T("Java");
+ //
+ class mkpath {
+ public:
+ operator const tstring& () const {
+ return path;
+ }
+
+ mkpath& operator << (const tstring& p) {
+ path = combinePath(path, p);
+ return *this;
+ }
+
+ // mimic std::string
+ const tstring::value_type* c_str() const {
+ return path.c_str();
+ }
+ private:
+ tstring path;
+ };
+
+ struct Directory {
+ Directory() {
+ }
+
+ Directory(const tstring &parent, const tstring &subdir) : parent(parent), subdir(subdir) {
+ }
+
+ operator tstring () const {
+ return getPath();
+ }
+
+ tstring getPath() const {
+ return combinePath(parent, subdir);
+ }
+
+ bool empty() const {
+ return (parent.empty() && subdir.empty());
+ }
+
+ tstring parent;
+ tstring subdir;
+ };
+
+ // Deletes list of files and directories in batch mode.
+ // Registered files and directories are deleted when destructor is called.
+ // Order or delete operations is following:
+ // - delete items registered with appendFile() calls;
+ // - delete items registered with appendAllFilesInDirectory() calls;
+ // - delete items registered with appendRecursiveDirectory() calls;
+ // - delete items registered with appendEmptyDirectory() calls.
+ class Deleter {
+ public:
+ Deleter() {
+ }
+
+ ~Deleter() {
+ execute();
+ }
+
+ typedef std::pair<tstring, int> Path;
+ typedef std::vector<Path> Paths;
+
+ /**
+ * Appends all records from the given deleter Deleter into this Deleter
+ * instance. On success array with records in the passed in Deleter
+ * instance is emptied.
+ */
+ Deleter& appendFrom(Deleter& other) {
+ Paths tmp(paths);
+ tmp.insert(tmp.end(), other.paths.begin(), other.paths.end());
+ Paths empty;
+ other.paths.swap(empty);
+ paths.swap(tmp);
+ return *this;
+ }
+
+ // Schedule file for deletion.
+ Deleter& appendFile(const tstring& path);
+
+ // Schedule files for deletion.
+ template <class It>
+ Deleter& appendFiles(It b, It e) {
+ for (It it = b; it != e; ++it) {
+ appendFile(*it);
+ }
+ return *this;
+ }
+
+ // Schedule files for deletion in the given directory.
+ template <class It>
+ Deleter& appendFiles(const tstring& dirname, It b, It e) {
+ for (It it = b; it != e; ++it) {
+ appendFile(FileUtils::mkpath() << dirname << *it);
+ }
+ return *this;
+ }
+
+ // 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)
+ // with Directory(dirname(path), basename(path)).
+ Deleter& appendEmptyDirectory(const tstring& path);
+
+ // Schedule all file from the given directory for deletion.
+ Deleter& appendAllFilesInDirectory(const tstring& path);
+
+ // Schedule directory for recursive deletion.
+ Deleter& appendRecursiveDirectory(const tstring& path);
+
+ void cancel() {
+ paths.clear();
+ }
+
+ // Deletes scheduled files and directories. After this function
+ // is called internal list of scheduled items is emptied.
+ void execute();
+
+ private:
+ Paths paths;
+ };
+
+
+ /**
+ * Helper to write chunks of data into binary file.
+ * Creates temporary file in the same folder with destination file.
+ * All subsequent requests to save data chunks are redirected to temporary
+ * file. finalize() method closes temporary file stream and renames
+ * temporary file.
+ * If finalize() method is not called, temporary file is deleted in
+ * ~FileWriter(), destination file is not touched.
+ */
+ class FileWriter {
+ public:
+ explicit FileWriter(const tstring& path);
+
+ FileWriter& write(const void* buf, size_t bytes);
+
+ template <class Ctnr>
+ FileWriter& write(const Ctnr& buf) {
+ return write(buf.data(),
+ buf.size() * sizeof(typename Ctnr::value_type));
+ }
+
+ void finalize();
+
+ private:
+ // Not accessible by design!
+ FileWriter& write(const std::wstring& str);
+
+ private:
+ tstring tmpFile;
+ Deleter cleaner;
+ std::ofstream tmp;
+ tstring dstPath;
+ };
+} // FileUtils
+
+#endif // FILEUTILS_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/libjpackage/Log.cpp Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,207 @@
+/*
+ * 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 "Log.h"
+#include "SysInfo.h"
+#include "FileUtils.h"
+
+
+namespace {
+ //
+ // IMPORTANT: Static objects with non-trivial constructors are NOT allowed
+ // in logger module. Allocate buffers only and do lazy initialization of
+ // globals in Logger::getDefault().
+ //
+ // Logging subsystem is used almost in every module, and logging API can be
+ // called from constructors of static objects in various modules. As
+ // ordering of static objects initialization between modules is undefined,
+ // this means some module may call logging api before logging static
+ // variables are initialized if any. This will result in AV. To avoid such
+ // use cases keep logging module free from static variables that require
+ // initialization with functions called by CRT.
+ //
+
+ // by default log everything
+ const Logger::LogLevel defaultLogLevel = Logger::LOG_TRACE;
+
+ char defaultLogAppenderMemory[sizeof(StderrLogAppender)] = {};
+
+ char defaultLoggerMemory[sizeof(Logger)] = {};
+
+ NopLogAppender nopLogApender;
+
+ LPCTSTR getLogLevelStr(Logger::LogLevel level) {
+ switch (level) {
+ case Logger::LOG_TRACE:
+ return _T("TRACE");
+ case Logger::LOG_INFO:
+ return _T("INFO");
+ case Logger::LOG_WARNING:
+ return _T("WARNING");
+ case Logger::LOG_ERROR:
+ return _T("ERROR");
+ }
+ return _T("UNKNOWN");
+ }
+
+ tstring retrieveModuleName() {
+ try {
+ return FileUtils::basename(SysInfo::getCurrentModulePath());
+ } catch (const std::exception&) {
+ return _T("Unknown");
+ }
+ }
+
+ TCHAR moduleName[MAX_PATH] = { 'U', 'n', 'k', 'o', 'w', 'n', TCHAR(0) };
+
+ const LPCTSTR format = _T("[%04u/%02u/%02u %02u:%02u:%02u.%03u, %s (PID: %u, TID: %u), %s:%u (%s)]\n\t%s: %s\n");
+
+ enum State { NotInitialized, Initializing, Initialized };
+ State state = NotInitialized;
+}
+
+
+LogEvent::LogEvent() {
+ memset(this, 0, sizeof(*this));
+ moduleName = tstring();
+ logLevel = tstring();
+ fileName = tstring();
+ funcName = tstring();
+ message = tstring();
+}
+
+
+StderrLogAppender::StderrLogAppender() {
+}
+
+
+/*static*/
+Logger& Logger::defaultLogger()
+{
+ Logger* reply = reinterpret_cast<Logger*>(defaultLoggerMemory);
+
+ if (!reply->appender) {
+ // Memory leak by design. Not an issue at all as this is global
+ // object. OS will do resources clean up anyways when application
+ // terminates and the default log appender should live as long as
+ // application lives.
+ reply->appender = new (defaultLogAppenderMemory) StderrLogAppender();
+ }
+
+ if (Initializing == state) {
+ // Recursive call to Logger::defaultLogger.
+ moduleName[0] = TCHAR(0);
+ } else if (NotInitialized == state) {
+ state = Initializing;
+
+ tstring mname = retrieveModuleName();
+ mname.resize(_countof(moduleName) - 1);
+ std::memcpy(moduleName, mname.c_str(), mname.size());
+ moduleName[mname.size()] = TCHAR(0);
+
+ // if JPACKAGE_DEBUG environment variable is NOT set to "true" disable
+ // logging.
+ if (SysInfo::getEnvVariable(std::nothrow, L"JPACKAGE_DEBUG") != L"true") {
+ reply->appender = &nopLogApender;
+ }
+
+ state = Initialized;
+ }
+
+ return *reply;
+}
+
+Logger::Logger(LogAppender& appender, LogLevel logLevel)
+ : level(logLevel), appender(&appender)
+{
+}
+
+void Logger::setLogLevel(LogLevel logLevel)
+{
+ level = logLevel;
+}
+
+Logger::~Logger()
+{
+}
+
+
+bool Logger::isLoggable(LogLevel logLevel) const
+{
+ return logLevel >= level;
+}
+
+void Logger::log(LogLevel logLevel, LPCTSTR fileName, int lineNum, LPCTSTR funcName, const tstring& message) const
+{
+ LogEvent logEvent;
+
+ // [YYYY/MM/DD HH:MM:SS.ms, <module> (PID: processID, TID: threadID), fileName:lineNum (funcName)]
+ // <tab>LEVEL: message
+ GetLocalTime(&logEvent.ts);
+
+ logEvent.pid = GetCurrentProcessId();
+ logEvent.tid = GetCurrentThreadId();
+ logEvent.moduleName = moduleName;
+ logEvent.fileName = FileUtils::basename(fileName);
+ logEvent.funcName = funcName;
+ logEvent.logLevel = getLogLevelStr(logLevel);
+ logEvent.lineNum = lineNum;
+ logEvent.message = message;
+
+ appender->append(logEvent);
+}
+
+
+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
+ v.moduleName.c_str(), v.pid, v.tid,
+ v.fileName.c_str(), v.lineNum, v.funcName.c_str(),
+ v.logLevel.c_str(),
+ v.message.c_str());
+
+ std::cerr << tstrings::toUtf8(out);
+}
+
+
+// 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))
+{
+ if (needLog) {
+ log.log(level, file.c_str(), line, func.c_str(), tstrings::any() << "Entering " << scope);
+ }
+}
+
+Logger::ScopeTracer::~ScopeTracer() {
+ if (needLog) {
+ // 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 << ")");
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/libjpackage/Log.h Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,198 @@
+/*
+ * 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 __LOG_H_INCLUDED_
+#define __LOG_H_INCLUDED_
+
+#include <windows.h>
+#include "tstrings.h"
+
+
+/* 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.
+ *
+ * Logger fileName specifies only file name,
+ * full path for the log file depends on the platform (usually value of the TMP env. var)
+ */
+
+
+struct LogEvent {
+ SYSTEMTIME ts;
+ long tid;
+ long pid;
+ tstring moduleName;
+ tstring logLevel;
+ tstring fileName;
+ int lineNum;
+ tstring funcName;
+ tstring message;
+
+ LogEvent();
+};
+
+
+class LogAppender {
+public:
+ virtual ~LogAppender() {
+ }
+ virtual void append(const LogEvent& v) = 0;
+};
+
+
+class NopLogAppender: public LogAppender {
+public:
+ virtual void append(const LogEvent& v) {};
+};
+
+
+class TeeLogAppender: public LogAppender {
+public:
+ TeeLogAppender(LogAppender* first, LogAppender* second):
+ first(first), second(second) {
+ }
+ virtual ~TeeLogAppender() {
+ }
+ virtual void append(const LogEvent& v) {
+ if (first) {
+ first->append(v);
+ }
+ if (second) {
+ second->append(v);
+ }
+ }
+private:
+ LogAppender* first;
+ LogAppender* second;
+};
+
+
+/**
+ * Writes log events to stderr.
+ */
+class StderrLogAppender: public LogAppender {
+public:
+ explicit StderrLogAppender();
+
+ virtual void append(const LogEvent& v);
+};
+
+
+class Logger {
+public:
+ enum LogLevel {
+ LOG_TRACE,
+ LOG_INFO,
+ LOG_WARNING,
+ LOG_ERROR
+ };
+
+ static Logger& defaultLogger();
+
+ explicit Logger(LogAppender& appender, LogLevel logLevel = LOG_TRACE);
+ ~Logger();
+
+ LogAppender& setAppender(LogAppender& v) {
+ LogAppender& oldAppender = *appender;
+ appender = &v;
+ return oldAppender;
+ }
+
+ LogAppender& getAppender() const {
+ return *appender;
+ }
+
+ 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 {
+ return log(logLevel, fileName, lineNum, funcName, message.tstr());
+ }
+ void log(LogLevel logLevel, LPCTSTR fileName, int lineNum,
+ 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();
+
+ private:
+ const Logger &log;
+ const LogLevel level;
+ const bool needLog;
+ const tstring file;
+ const int line;
+ const tstring func;
+ const tstring scope;
+ };
+
+private:
+ LogLevel level;
+ LogAppender* appender;
+};
+
+
+// base logging macro
+#define LOGGER_LOG(logger, logLevel, message) \
+ do { \
+ if (logger.isLoggable(logLevel)) { \
+ logger.log(logLevel, _T(__FILE__), __LINE__, _T(__FUNCTION__), message); \
+ } \
+ } while(false)
+
+
+// custom logger macros
+#define LOGGER_TRACE(logger, message) LOGGER_LOG(logger, Logger::LOG_TRACE, message)
+#define LOGGER_INFO(logger, message) LOGGER_LOG(logger, Logger::LOG_INFO, message)
+#define LOGGER_WARNING(logger, message) LOGGER_LOG(logger, Logger::LOG_WARNING, message)
+#define LOGGER_ERROR(logger, message) LOGGER_LOG(logger, Logger::LOG_ERROR, message)
+// scope tracing macros
+#define LOGGER_TRACE_SCOPE(logger, scopeName) \
+ Logger::ScopeTracer tracer__COUNTER__(logger, Logger::LOG_TRACE, _T(__FILE__), __LINE__, _T(__FUNCTION__), scopeName)
+#define LOGGER_TRACE_FUNCTION(logger) LOGGER_TRACE_SCOPE(logger, _T(__FUNCTION__))
+
+
+// default logger macros
+#define LOG_TRACE(message) LOGGER_LOG(Logger::defaultLogger(), Logger::LOG_TRACE, message)
+#define LOG_INFO(message) LOGGER_LOG(Logger::defaultLogger(), Logger::LOG_INFO, message)
+#define LOG_WARNING(message) LOGGER_LOG(Logger::defaultLogger(), Logger::LOG_WARNING, message)
+#define LOG_ERROR(message) LOGGER_LOG(Logger::defaultLogger(), Logger::LOG_ERROR, message)
+// scope tracing macros
+// logs (_T("Entering ") + scopeName) at the beging, (_T("Exiting ") + scopeName) at the end of scope
+#define LOG_TRACE_SCOPE(scopeName) LOGGER_TRACE_SCOPE(Logger::defaultLogger(), scopeName)
+// logs (_T("Entering ") + functionName) at the beging, (_T("Exiting ") + __FUNCTION__) at the end of scope
+#define LOG_TRACE_FUNCTION() LOGGER_TRACE_FUNCTION(Logger::defaultLogger())
+
+
+#endif // __LOG_H_INCLUDED_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/libjpackage/ResourceEditor.cpp Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +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 <algorithm>
+#include <fstream>
+#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<size_t>(v);
+ theType = printer.str();
+ theTypePtr = MAKEINTRESOURCE(static_cast<DWORD>(reinterpret_cast<DWORD_PTR>(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<size_t>(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<BYTE> ByteArray;
+ ByteArray buf;
+ if (size <= 0) {
+ // Read the entire stream.
+ buf = ByteArray((std::istreambuf_iterator<char>(srcStream)),
+ std::istreambuf_iterator<char>());
+ } else {
+ buf.resize(size_t(size));
+ srcStream.read(reinterpret_cast<char*>(buf.data()), size);
+ }
+
+ auto reply = UpdateResource(dstBinary.get(), theTypePtr, theIdPtr, lang,
+ buf.data(), static_cast<DWORD>(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);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/libjpackage/ResourceEditor.h Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +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 <windows.h>
+#include <vector>
+#include <string>
+
+
+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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/libjpackage/SourceCodePos.h Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,53 @@
+/*
+ * 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 SourceCodePos_h
+#define SourceCodePos_h
+
+
+//
+// Position in source code.
+//
+
+struct SourceCodePos
+{
+ SourceCodePos(const char* fl, const char* fnc, int l):
+ file(fl), func(fnc), lno(l)
+ {
+ }
+
+ const char* file;
+ const char* func;
+ int lno;
+};
+
+
+// Initializes SourceCodePos instance with the
+// information from the point of calling.
+#define JP_SOURCE_CODE_POS SourceCodePos(__FILE__, __FUNCTION__, __LINE__)
+
+
+#endif // #ifndef SourceCodePos_h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/libjpackage/SysInfo.h Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,78 @@
+/*
+ * 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 SYSINFO_H
+#define SYSINFO_H
+
+#include "tstrings.h"
+
+
+//
+// This namespace provides information about environment in which
+// the current application runs.
+// It is for general purpose use.
+// Functions in this namespaces are just queries about the environment.
+// Functions that change the existing environment like file or directory
+// creation should not be added to this namespace.
+//
+namespace SysInfo {
+ /**
+ * Returns temp dir (for the current user).
+ */
+ tstring getTempDir();
+
+ /**
+ * Returns absolute path to the process executable.
+ */
+ tstring getProcessModulePath();
+
+ /**
+ * Returns absolute path to the current executable module.
+ */
+ tstring getCurrentModulePath();
+
+ /**
+ * Returns value of environment variable with the given name.
+ * Throws exception if variable is not set or any other error occurred
+ * reading the value.
+ */
+ tstring getEnvVariable(const tstring& name);
+
+ /**
+ * Returns value of environment variable with the given name.
+ * Returns value of 'defValue' parameter if variable is not set or any
+ * other error occurred reading the value.
+ */
+ tstring getEnvVariable(const std::nothrow_t&, const tstring& name,
+ const tstring& defValue=tstring());
+
+ /**
+ * Returns 'true' if environment variable with the given name is set.
+ */
+ bool isEnvVariableSet(const tstring& name);
+}
+
+#endif // SYSINFO_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/libjpackage/UniqueHandle.h Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +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 <windows.h>
+#include <memory>
+
+
+struct WndHandleDeleter {
+ typedef HANDLE pointer;
+
+ void operator()(HANDLE h) {
+ ::CloseHandle(h);
+ }
+};
+
+typedef std::unique_ptr<HANDLE, WndHandleDeleter> UniqueHandle;
+
+#endif // #ifndef UNIQUEHANDLE_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/libjpackage/WinErrorHandling.cpp Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,125 @@
+/*
+ * 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 "WinErrorHandling.h"
+#include "Log.h"
+#include "SysInfo.h"
+#include "FileUtils.h"
+
+
+namespace {
+
+std::string makeMessage(const std::string& msg, const char* label,
+ const void* c, DWORD errorCode) {
+ std::ostringstream err;
+ err << (label ? label : "Some error") << " [" << errorCode << "]";
+
+ HMODULE hmodule = NULL;
+ if (c) {
+ GetModuleHandleEx(
+ GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+ reinterpret_cast<LPCTSTR>(c),
+ &hmodule);
+
+ if (!hmodule) {
+ LOG_WARNING(tstrings::any() << "GetModuleHandleEx() failed for " << c << " address.");
+ }
+ }
+ if (hmodule || !c) {
+ err << "(" << SysError::getSysErrorMessage(errorCode, hmodule) << ")";
+ }
+
+ return joinErrorMessages(msg, err.str());
+}
+
+
+std::wstring getSystemMessageDescription(DWORD messageId, HMODULE moduleHandle) {
+ LPWSTR pMsg = NULL;
+ std::wstring descr;
+
+ // we always retrieve UNICODE description from system,
+ // convert it to utf8 if UNICODE is not defined
+
+ 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);
+ if (res > 0) {
+ // replace all non-printed chars with space
+ for (DWORD i=0; i<res; i++) {
+ if (pMsg[i] < L' ') {
+ pMsg[i] = L' ';
+ }
+ }
+ // trim right (spaces and dots)
+ for (DWORD i=res; i>0; i--) {
+ if (pMsg[i] > L' ' && pMsg[i] != L'.') {
+ break;
+ }
+ pMsg[i] = 0;
+ }
+
+ descr = pMsg;
+
+ LocalFree(pMsg);
+ } else {
+ // if we fail to get description for specific moduleHandle,
+ // try to get "common" description.
+ if (moduleHandle != NULL) {
+ moduleHandle = NULL;
+ continue;
+ }
+ descr = L"No description available";
+ }
+ break;
+ }
+
+ return descr;
+}
+
+} // namespace
+
+
+SysError::SysError(const tstrings::any& msg, const void* caller, DWORD ec,
+ const char* label):
+ std::runtime_error(makeMessage(msg.str(), label, caller, ec)) {
+}
+
+std::wstring SysError::getSysErrorMessage(DWORD errCode, HMODULE moduleHandle) {
+ tstrings::any msg;
+ msg << "system error " << errCode
+ << " (" << getSystemMessageDescription(errCode, moduleHandle) << ")";
+ return msg.tstr();
+}
+
+std::wstring SysError::getComErrorMessage(HRESULT hr) {
+ HRESULT hrOrig = hr;
+ // for FACILITY_WIN32 facility we need to reset hiword
+ if(HRESULT_FACILITY(hr) == FACILITY_WIN32) {
+ hr = HRESULT_CODE(hr);
+ }
+ return tstrings::format(_T("COM error 0x%08X (%s)"), hrOrig, getSystemMessageDescription(hr, NULL));
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/libjpackage/WinErrorHandling.h Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,48 @@
+/*
+ * 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 WinErrorHandling_h
+#define WinErrorHandling_h
+
+
+#include "ErrorHandling.h"
+
+
+class SysError : public std::runtime_error {
+public:
+ SysError(const tstrings::any& msg, const void* caller,
+ DWORD errorCode=GetLastError(), const char* label="System error");
+
+ // returns string "system error <errCode> (error_description)"
+ // in UNICODE is not defined, the string returned is utf8-encoded
+ static std::wstring getSysErrorMessage(DWORD errCode = GetLastError(), HMODULE moduleHandle = NULL);
+
+ // returns string "COM error 0x<hr> (error_description)"
+ // in UNICODE is not defined, the string returned is utf8-encoded
+ static std::wstring getComErrorMessage(HRESULT hr);
+};
+
+#endif // #ifndef WinErrorHandling_h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/libjpackage/WinSysInfo.cpp Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,174 @@
+/*
+ * 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 "WinSysInfo.h"
+#include "FileUtils.h"
+#include "WinErrorHandling.h"
+
+namespace SysInfo {
+
+tstring getTempDir() {
+ std::vector<TCHAR> buffer(MAX_PATH);
+ DWORD res = GetTempPath(static_cast<DWORD>(buffer.size()), buffer.data());
+ if (res > buffer.size()) {
+ buffer.resize(res);
+ GetTempPath(static_cast<DWORD>(buffer.size()), buffer.data());
+ }
+ return FileUtils::removeTrailingSlash(buffer.data());
+}
+
+namespace {
+
+template <class Func>
+tstring getSystemDirImpl(Func func, const std::string& label) {
+ std::vector<TCHAR> buffer(MAX_PATH);
+ for (int i=0; i<2; i++) {
+ DWORD res = func(buffer.data(), static_cast<DWORD>(buffer.size()));
+ if (!res) {
+ JP_THROW(SysError(label + " failed", func));
+ }
+ if (res < buffer.size()) {
+ return FileUtils::removeTrailingSlash(buffer.data());
+ }
+ buffer.resize(res + 1);
+ }
+ JP_THROW("Unexpected reply from" + label);
+}
+
+} // namespace
+
+tstring getSystem32Dir() {
+ return getSystemDirImpl(GetSystemDirectory, "GetSystemDirectory");
+}
+
+tstring getWIPath() {
+ return FileUtils::mkpath() << getSystem32Dir() << _T("msiexec.exe");
+}
+
+namespace {
+
+tstring getModulePath(HMODULE h)
+{
+ std::vector<TCHAR> buf(MAX_PATH);
+ DWORD len = 0;
+ while (true) {
+ len = GetModuleFileName(h, buf.data(), (DWORD)buf.size());
+ if (len < buf.size()) {
+ break;
+ }
+ // buffer is too small, increase it
+ buf.resize(buf.size() * 2);
+ }
+
+ if (len == 0) {
+ // error occured
+ JP_THROW(SysError("GetModuleFileName failed", GetModuleFileName));
+ }
+ return tstring(buf.begin(), buf.begin() + len);
+}
+
+} // namespace
+
+tstring getProcessModulePath() {
+ return getModulePath(NULL);
+}
+
+HMODULE getCurrentModuleHandle()
+{
+ // get module handle for the address of this function
+ LPCWSTR address = reinterpret_cast<LPCWSTR>(getCurrentModuleHandle);
+ HMODULE hmodule = NULL;
+ 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));
+ }
+ return hmodule;
+}
+
+tstring getCurrentModulePath()
+{
+ return getModulePath(getCurrentModuleHandle());
+}
+
+namespace {
+
+tstring getEnvVariableImpl(const tstring& name, bool* errorOccured=0) {
+ std::vector<TCHAR> buf(10);
+ SetLastError(ERROR_SUCCESS);
+ const DWORD size = GetEnvironmentVariable(name.c_str(), buf.data(),
+ DWORD(buf.size()));
+ if (GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
+ if (errorOccured) {
+ *errorOccured = true;
+ return tstring();
+ }
+ JP_THROW(SysError(tstrings::any() << "GetEnvironmentVariable("
+ << name << ") failed. Variable not set", GetEnvironmentVariable));
+ }
+
+ if (size > buf.size()) {
+ buf.resize(size);
+ GetEnvironmentVariable(name.c_str(), buf.data(), DWORD(buf.size()));
+ if (GetLastError() != ERROR_SUCCESS) {
+ if (errorOccured) {
+ *errorOccured = true;
+ return tstring();
+ }
+ JP_THROW(SysError(tstrings::any() << "GetEnvironmentVariable("
+ << name << ") failed", GetEnvironmentVariable));
+ }
+ }
+
+ if (errorOccured) {
+ *errorOccured = false;
+ }
+ return tstring(buf.data());
+}
+
+} // namespace
+
+tstring getEnvVariable(const tstring& name) {
+ return getEnvVariableImpl(name);
+}
+
+tstring getEnvVariable(const std::nothrow_t&, const tstring& name,
+ const tstring& defValue) {
+ bool errorOccured = false;
+ const tstring reply = getEnvVariableImpl(name, &errorOccured);
+ if (errorOccured) {
+ return defValue;
+ }
+ return reply;
+}
+
+bool isEnvVariableSet(const tstring& name) {
+ TCHAR unused[1];
+ SetLastError(ERROR_SUCCESS);
+ GetEnvironmentVariable(name.c_str(), unused, _countof(unused));
+ return GetLastError() != ERROR_ENVVAR_NOT_FOUND;
+}
+
+} // end of namespace SysInfo
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/libjpackage/WinSysInfo.h Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,49 @@
+/*
+ * 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 WINSYSINFO_H
+#define WINSYSINFO_H
+
+#include "SysInfo.h"
+
+
+//
+// Windows specific SysInfo.
+//
+namespace SysInfo {
+ // gets Windows System folder. A typical path is C:\Windows\System32.
+ tstring getSystem32Dir();
+
+ // returns full path to msiexec.exe executable
+ tstring getWIPath();
+
+ // Returns handle of the current module (exe or dll).
+ // The function assumes this code is statically linked to the module.
+ HMODULE getCurrentModuleHandle();
+}
+
+
+#endif // WINSYSINFO_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/libjpackage/tstrings.cpp Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,280 @@
+/*
+ * 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 <stdio.h>
+#include <stdarg.h>
+#include <stdexcept>
+#include <algorithm>
+
+#include "tstrings.h"
+#include "ErrorHandling.h"
+
+
+namespace tstrings {
+
+/* Create formatted string
+ */
+tstring unsafe_format(tstring::const_pointer format, ...) {
+ if (!format) {
+ throw std::invalid_argument("Destination buffer can't be NULL");
+ }
+
+ tstring fmtout;
+ int ret;
+ const int inc = 256;
+
+ va_list args;
+ va_start(args, format);
+ do {
+ fmtout.resize(fmtout.size() + inc);
+#ifdef _MSC_VER
+ ret = _vsntprintf_s(&*fmtout.begin(), fmtout.size(), _TRUNCATE, format, args);
+#else
+ // With g++ this compiles only with '-std=gnu++0x' option
+ ret = vsnprintf(&*fmtout.begin(), fmtout.size(), format, args);
+#endif
+ } while(-1 == ret);
+ va_end(args);
+
+ //update string size by actual value
+ fmtout.resize(ret);
+
+ return fmtout;
+}
+
+/*
+ * Tests if two strings are equal according to CompareType.
+ *
+ * a - string to compare
+ * b - string to compare
+ * ct - CASE_SENSITIVE: case sensitive comparing type
+ * IGNORE_CASE: case insensitive comparing type
+ */
+bool equals(const tstring& a, const tstring& b, const CompareType ct) {
+ if (IGNORE_CASE==ct) {
+ return toLower(a) == toLower(b);
+ }
+ return a == b;
+}
+
+bool startsWith(const tstring &str, const tstring &substr, const CompareType ct)
+{
+ if (str.size() < substr.size()) {
+ return false;
+ }
+ const tstring startOfStr = str.substr(0, substr.size());
+ return tstrings::equals(startOfStr, substr, ct);
+}
+
+bool endsWith(const tstring &str, const tstring &substr, const CompareType ct)
+{
+ if (str.size() < substr.size()) {
+ return false;
+ }
+ const tstring endOfStr = str.substr(str.size() - substr.size());
+ return tstrings::equals(endOfStr, substr, ct);
+}
+
+/*
+ * Split string into a vector with given delimiter string
+ *
+ * strVector - string vector to store split tstring
+ * str - string to split
+ * delimiter - delimiter to split the string around
+ * st - ST_ALL: return value includes an empty string
+ * ST_EXCEPT_EMPTY_STRING: return value does not include an empty string
+ *
+ * Note: It does not support multiple delimiters
+ */
+void split(tstring_array &strVector, const tstring &str,
+ const tstring &delimiter, const SplitType st) {
+ tstring::size_type start = 0, end = 0, length = str.length();
+
+ if (length == 0 || delimiter.length() == 0) {
+ return;
+ }
+
+ end = str.find(delimiter, start);
+ while(end != tstring::npos) {
+ if(st == ST_ALL || end - start > 1 ) {
+ strVector.push_back(str.substr(start, end == tstring::npos ?
+ tstring::npos : end - start));
+ }
+ start = end > (tstring::npos - delimiter.size()) ?
+ tstring::npos : end + delimiter.size();
+ end = str.find(delimiter, start);
+ }
+
+ if(st == ST_ALL || start < length) {
+ strVector.push_back(str.substr(start, length - start));
+ }
+}
+
+/*
+ * Convert uppercase letters to lowercase
+ */
+tstring toLower(const tstring& str) {
+ tstring lower(str);
+ tstring::iterator ok = std::transform(lower.begin(), lower.end(),
+ lower.begin(), tolower);
+ if (ok!=lower.end()) {
+ lower.resize(0);
+ }
+ return lower;
+}
+
+
+/*
+ * Replace all substring occurrences in a tstring.
+ * If 'str' or 'search' is empty the function returns 'str'.
+ * The given 'str' remains unchanged in any case.
+ * The function returns changed copy of 'str'.
+ */
+tstring replace(const tstring &str, const tstring &search, const tstring &replace)
+{
+ if (search.empty()) {
+ return str;
+ }
+
+ tstring s(str);
+
+ for (size_t pos = 0; ; pos += replace.length()) {
+ pos = s.find(search, pos);
+ if (pos == tstring::npos) {
+ break;
+ }
+ s.erase(pos, search.length());
+ s.insert(pos, replace);
+ }
+ return s;
+}
+
+
+/*
+ * Remove trailing spaces
+ */
+
+tstring trim(const tstring& str, const tstring& whitespace) {
+ const size_t strBegin = str.find_first_not_of(whitespace);
+ if (strBegin == std::string::npos) {
+ return tstring(); // no content
+ }
+
+ const size_t strEnd = str.find_last_not_of(whitespace);
+ const size_t strRange = strEnd - strBegin + 1;
+
+ return str.substr(strBegin, strRange);
+}
+
+} // namespace tstrings
+
+
+#ifdef TSTRINGS_WITH_WCHAR
+namespace tstrings {
+
+namespace {
+/*
+ * Converts UTF16-encoded string into multi-byte string of the given encoding.
+ */
+std::string toMultiByte(const std::wstring& utf16str, int encoding) {
+ std::string reply;
+ do {
+ int cm = WideCharToMultiByte(encoding,
+ 0,
+ utf16str.c_str(),
+ int(utf16str.size()),
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ if (cm < 0) {
+ JP_THROW("Unexpected reply from WideCharToMultiByte()");
+ }
+ if (0 == cm) {
+ break;
+ }
+
+ reply.resize(cm);
+ int cm2 = WideCharToMultiByte(encoding,
+ 0,
+ utf16str.c_str(),
+ int(utf16str.size()),
+ &*reply.begin(),
+ cm,
+ NULL,
+ NULL);
+ if (cm != cm2) {
+ JP_THROW("Unexpected reply from WideCharToMultiByte()");
+ }
+ } while(0);
+
+ return reply;
+}
+
+/*
+ * Converts multi-byte string of the given encoding into UTF16-encoded string.
+ */
+std::wstring fromMultiByte(const std::string& str, int encoding) {
+ std::wstring utf16;
+ do {
+ int cw = MultiByteToWideChar(encoding,
+ MB_ERR_INVALID_CHARS,
+ str.c_str(),
+ int(str.size()),
+ NULL,
+ 0);
+ if (cw < 0) {
+ JP_THROW("Unexpected reply from MultiByteToWideChar()");
+ }
+ if (0 == cw) {
+ break;
+ }
+
+ utf16.resize(cw);
+ int cw2 = MultiByteToWideChar(encoding,
+ MB_ERR_INVALID_CHARS,
+ str.c_str(),
+ int(str.size()),
+ &*utf16.begin(),
+ cw);
+ if (cw != cw2) {
+ JP_THROW("Unexpected reply from MultiByteToWideChar()");
+ }
+ } while(0);
+
+ return utf16;
+}
+} // namespace
+
+std::string toUtf8(const std::wstring& utf16str) {
+ return toMultiByte(utf16str, CP_UTF8);
+}
+
+std::wstring toUtf16(const std::string& utf8str) {
+ return fromMultiByte(utf8str, CP_UTF8);
+}
+
+} // namespace tstrings
+#endif // ifdef TSTRINGS_WITH_WCHAR
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/libjpackage/tstrings.h Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,415 @@
+/*
+ * 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 TSTRINGS_H
+#define TSTRINGS_H
+
+#ifdef _MSC_VER
+# define TSTRINGS_WITH_WCHAR
+#endif
+
+#ifdef TSTRINGS_WITH_WCHAR
+#include <windows.h>
+#include <tchar.h>
+// Want compiler issue C4995 warnings for encounters of deprecated functions.
+#include <strsafe.h>
+#endif
+
+// STL's string header depends on deprecated functions.
+// We don't care about warnings from STL header, so disable them locally.
+#ifdef _MSC_VER
+# pragma warning(push)
+# pragma warning(disable:4995)
+#endif
+
+#include <string>
+#include <sstream>
+#include <iostream>
+#include <vector>
+
+#ifdef _MSC_VER
+# pragma warning(pop)
+#endif
+
+
+#ifndef _T
+# define _T(x) x
+#endif
+
+
+#ifdef TSTRINGS_WITH_WCHAR
+typedef std::wstring tstring;
+typedef std::wostringstream tostringstream;
+typedef std::wistringstream tistringstream;
+typedef std::wstringstream tstringstream;
+typedef std::wistream tistream;
+typedef std::wostream tostream;
+typedef std::wiostream tiostream;
+typedef std::wios tios;
+#else
+typedef std::string tstring;
+typedef std::ostringstream tostringstream;
+typedef std::istringstream tistringstream;
+typedef std::stringstream tstringstream;
+typedef std::istream tistream;
+typedef std::ostream tostream;
+typedef std::iostream tiostream;
+typedef std::ios tios;
+
+typedef const char* LPCTSTR;
+typedef char TCHAR;
+#endif
+
+// frequently used "array of tstrings" type
+typedef std::vector<tstring> tstring_array;
+
+namespace tstrings {
+ 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);
+
+ 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) {
+ tstring_array result;
+ split(result, str, delimiter, st);
+ return result;
+ }
+ tstring trim(const tstring& str, const tstring& whitespace = _T(" \t"));
+
+ /**
+ * Writes sequence of values from [b, e) range into string buffer inserting
+ * 'delimiter' after each value except of the last one.
+ * Returns contents of string buffer.
+ */
+ template <class It>
+ tstring join(It b, It e, const tstring& delimiter=tstring()) {
+ tostringstream buf;
+ if (b != e) {
+ for (;;) {
+ buf << *b;
+ if (++b == e) {
+ break;
+ }
+ buf << delimiter;
+ }
+ }
+ return buf.str();
+ }
+
+ tstring toLower(const tstring& str);
+
+ tstring replace(const tstring &str, const tstring &search, const tstring &replace);
+}
+
+
+namespace tstrings {
+ inline std::string toUtf8(const std::string& utf8str) { return utf8str; }
+
+#ifdef TSTRINGS_WITH_WCHAR
+ // conversion to Utf8
+ std::string toUtf8(const std::wstring& utf16str);
+
+ // conversion to Utf16
+ std::wstring toUtf16(const std::string& utf8str);
+
+ inline std::wstring fromUtf8(const std::string& utf8str) { return toUtf16(utf8str); }
+
+#else
+ inline std::string fromUtf8(const std::string& utf8str) { return utf8str; }
+#endif
+} // namespace tstrings
+
+
+namespace tstrings {
+namespace format_detail {
+
+ template <class T>
+ struct str_arg_value {
+ const tstring value;
+
+ str_arg_value(const std::string& v): value(fromUtf8(v)) {
+ }
+
+#ifdef TSTRINGS_WITH_WCHAR
+ str_arg_value(const std::wstring& v): value(v) {
+ }
+#endif
+
+ tstring::const_pointer operator () () const {
+ return value.c_str();
+ }
+ };
+
+ template <>
+ struct str_arg_value<tstring> {
+ const tstring::const_pointer value;
+
+ str_arg_value(const tstring& v): value(v.c_str()) {
+ }
+
+ str_arg_value(tstring::const_pointer v): value(v) {
+ }
+
+ tstring::const_pointer operator () () const {
+ return value;
+ }
+ };
+
+ inline str_arg_value<std::string> arg(const std::string& v) {
+ return v;
+ }
+
+ inline str_arg_value<std::string> arg(std::string::const_pointer v) {
+ return (v ? v : "(null)");
+ }
+
+#ifdef TSTRINGS_WITH_WCHAR
+ inline str_arg_value<std::wstring> arg(const std::wstring& v) {
+ return v;
+ }
+
+ inline str_arg_value<std::wstring> arg(std::wstring::const_pointer v) {
+ return (v ? v : L"(null)");
+ }
+#else
+ void arg(const std::wstring&); // Compilation error by design.
+ void arg(std::wstring::const_pointer); // Compilation error by design.
+#endif
+
+ template <class T>
+ struct arg_value {
+ arg_value(const T v): v(v) {
+ }
+ T operator () () const {
+ return v;
+ }
+ private:
+ const T v;
+ };
+
+ inline arg_value<int> arg(int v) {
+ return v;
+ }
+ inline arg_value<unsigned> arg(unsigned v) {
+ return v;
+ }
+ inline arg_value<long> arg(long v) {
+ return v;
+ }
+ inline arg_value<unsigned long> arg(unsigned long v) {
+ return v;
+ }
+ inline arg_value<long long> arg(long long v) {
+ return v;
+ }
+ inline arg_value<unsigned long long> arg(unsigned long long v) {
+ return v;
+ }
+ inline arg_value<float> arg(float v) {
+ return v;
+ }
+ inline arg_value<double> arg(double v) {
+ return v;
+ }
+ inline arg_value<bool> arg(bool v) {
+ return v;
+ }
+ inline arg_value<const void*> arg(const void* v) {
+ return v;
+ }
+
+} // namespace format_detail
+} // namespace tstrings
+
+
+namespace tstrings {
+ template <class T, class T2, class T3, class T4, class T5, class T6, class T7>
+ inline tstring format(const tstring& fmt, const T& v, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6, const T7& v7) {
+ return unsafe_format(fmt.c_str(), format_detail::arg(v)(),
+ format_detail::arg(v2)(),
+ format_detail::arg(v3)(),
+ format_detail::arg(v4)(),
+ format_detail::arg(v5)(),
+ format_detail::arg(v6)(),
+ format_detail::arg(v7)());
+ }
+
+ template <class T, class T2, class T3, class T4, class T5, class T6>
+ inline tstring format(const tstring& fmt, const T& v, const T2& v2, const T3& v3, const T4& v4, const T5& v5, const T6& v6) {
+ return unsafe_format(fmt.c_str(), format_detail::arg(v)(),
+ format_detail::arg(v2)(),
+ format_detail::arg(v3)(),
+ format_detail::arg(v4)(),
+ format_detail::arg(v5)(),
+ format_detail::arg(v6)());
+ }
+
+ template <class T, class T2, class T3, class T4, class T5>
+ inline tstring format(const tstring& fmt, const T& v, const T2& v2, const T3& v3, const T4& v4, const T5& v5) {
+ return unsafe_format(fmt.c_str(), format_detail::arg(v)(),
+ format_detail::arg(v2)(),
+ format_detail::arg(v3)(),
+ format_detail::arg(v4)(),
+ format_detail::arg(v5)());
+ }
+
+ template <class T, class T2, class T3, class T4>
+ inline tstring format(const tstring& fmt, const T& v, const T2& v2, const T3& v3, const T4& v4) {
+ return unsafe_format(fmt.c_str(), format_detail::arg(v)(),
+ format_detail::arg(v2)(),
+ format_detail::arg(v3)(),
+ format_detail::arg(v4)());
+ }
+
+ template <class T, class T2, class T3>
+ inline tstring format(const tstring& fmt, const T& v, const T2& v2, const T3& v3) {
+ return unsafe_format(fmt.c_str(), format_detail::arg(v)(),
+ format_detail::arg(v2)(),
+ format_detail::arg(v3)());
+ }
+
+ template <class T, class T2>
+ inline tstring format(const tstring& fmt, const T& v, const T2& v2) {
+ return unsafe_format(fmt.c_str(), format_detail::arg(v)(),
+ format_detail::arg(v2)());
+
+ }
+
+ template <class T>
+ inline tstring format(const tstring& fmt, const T& v) {
+ return unsafe_format(fmt.c_str(), format_detail::arg(v)());
+ }
+} // namespace tstrings
+
+
+namespace tstrings {
+ /**
+ * Buffer that accepts both std::wstring and std::string instances doing
+ * encoding conversions behind the scenes. All std::string-s assumed to be
+ * UTF8-encoded, all std::wstring-s assumed to be UTF16-encoded.
+ */
+ class any {
+ public:
+ any() {
+ }
+
+ any(std::string::const_pointer msg) {
+ data << fromUtf8(msg);
+ }
+
+ any(const std::string& msg) {
+ data << fromUtf8(msg);
+ }
+
+#ifdef TSTRINGS_WITH_WCHAR
+ any(std::wstring::const_pointer msg) {
+ data << msg;
+ }
+
+ any(const std::wstring& msg) {
+ data << msg;
+ }
+
+ any& operator << (const std::wstring& v) {
+ data << v;
+ return *this;
+ }
+
+ // need this specialization instead std::wstring::pointer,
+ // otherwise LPWSTR is handled as abstract pointer (void*)
+ any& operator << (LPWSTR v) {
+ data << (v ? v : L"NULL");
+ return *this;
+ }
+
+ // need this specialization instead std::wstring::const_pointer,
+ // otherwise LPCWSTR is handled as abstract pointer (const void*)
+ any& operator << (LPCWSTR v) {
+ data << (v ? v : L"NULL");
+ return *this;
+ }
+
+ std::wstring wstr() const {
+ return data.str();
+ }
+#endif
+
+ template <class T>
+ any& operator << (T v) {
+ data << v;
+ return *this;
+ }
+
+ any& operator << (tostream& (*pf)(tostream&)) {
+ data << pf;
+ return *this;
+ }
+
+ any& operator << (tios& (*pf)(tios&)) {
+ data << pf;
+ return *this;
+ }
+
+ any& operator << (std::ios_base& (*pf)(std::ios_base&)) {
+ data << pf;
+ return *this;
+ }
+
+ std::string str() const {
+ return toUtf8(data.str());
+ }
+
+ tstring tstr() const {
+ return data.str();
+ }
+
+ private:
+ tostringstream data;
+ };
+
+ inline tstring to_tstring(const any& val) {
+ return val.tstr();
+ }
+} // namespace tstrings
+
+
+inline std::ostream& operator << (std::ostream& os, const tstrings::any& buf) {
+ os << buf.str();
+ return os;
+}
+
+#ifdef TSTRINGS_WITH_WCHAR
+inline std::wostream& operator << (std::wostream& os, const tstrings::any& buf) {
+ os << buf.wstr();
+ return os;
+}
+#endif
+
+#endif //TSTRINGS_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/msiwrapper/Executor.cpp Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,129 @@
+/*
+ * 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 <algorithm>
+#include "Executor.h"
+#include "Log.h"
+#include "WinErrorHandling.h"
+
+
+namespace {
+
+void escapeArg(std::wstring& str) {
+ if (str.empty()) {
+ return;
+ }
+
+ if (str.front() == L'\"' && str.back() == L'\"' && str.size() > 1) {
+ return;
+ }
+
+ if (str.find_first_of(L" \t") != std::wstring::npos) {
+ str = L'"' + str + L'"';
+ }
+}
+
+} // namespace
+
+
+std::wstring Executor::args() const {
+ tstring_array tmpArgs;
+ // argv[0] is the module name.
+ tmpArgs.push_back(appPath);
+ tmpArgs.insert(tmpArgs.end(), argsArray.begin(), argsArray.end());
+
+ std::for_each(tmpArgs.begin(), tmpArgs.end(), escapeArg);
+ return tstrings::join(tmpArgs.begin(), tmpArgs.end(), _T(" "));
+}
+
+
+int Executor::execAndWaitForExit() const {
+ UniqueHandle h = startProcess();
+
+ const DWORD res = ::WaitForSingleObject(h.get(), INFINITE);
+ if (WAIT_FAILED == res) {
+ JP_THROW(SysError("WaitForSingleObject() failed", WaitForSingleObject));
+ }
+
+ DWORD exitCode = 0;
+ if (!GetExitCodeProcess(h.get(), &exitCode)) {
+ // Error reading process's exit code.
+ JP_THROW(SysError("GetExitCodeProcess() failed", GetExitCodeProcess));
+ }
+
+ const DWORD processId = GetProcessId(h.get());
+ if (!processId) {
+ JP_THROW(SysError("GetProcessId() failed.", GetProcessId));
+ }
+
+ LOG_TRACE(tstrings::any() << "Process with PID=" << processId
+ << " terminated. Exit code=" << exitCode);
+
+ return static_cast<int>(exitCode);
+}
+
+
+UniqueHandle Executor::startProcess() const {
+ const std::wstring argsStr = args();
+
+ std::vector<TCHAR> argsBuffer(argsStr.begin(), argsStr.end());
+ argsBuffer.push_back(0); // terminating '\0'
+
+ STARTUPINFO startupInfo;
+ ZeroMemory(&startupInfo, sizeof(startupInfo));
+ startupInfo.cb = sizeof(startupInfo);
+
+ PROCESS_INFORMATION processInfo;
+ ZeroMemory(&processInfo, sizeof(processInfo));
+
+ DWORD creationFlags = 0;
+
+ if (!theVisible) {
+ // For GUI applications.
+ startupInfo.dwFlags |= STARTF_USESHOWWINDOW;
+ startupInfo.wShowWindow = SW_HIDE;
+
+ // For console applications.
+ creationFlags |= CREATE_NO_WINDOW;
+ }
+
+ tstrings::any msg;
+ msg << "CreateProcess(" << appPath << ", " << argsStr << ")";
+
+ if (!CreateProcess(appPath.c_str(), argsBuffer.data(), NULL, NULL, FALSE,
+ creationFlags, NULL, NULL, &startupInfo, &processInfo)) {
+ msg << " failed";
+ JP_THROW(SysError(msg, CreateProcess));
+ }
+
+ msg << " succeeded; PID=" << processInfo.dwProcessId;
+ LOG_TRACE(msg);
+
+ // Close unneeded handles immediately.
+ UniqueHandle(processInfo.hThread);
+
+ // Return process handle.
+ return UniqueHandle(processInfo.hProcess);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/msiwrapper/Executor.h Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/msiwrapper/MsiWrapper.cpp Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,37 @@
+#include <windows.h>
+
+#include "WinSysInfo.h"
+#include "FileUtils.h"
+#include "Executor.h"
+#include "Resources.h"
+#include "WinErrorHandling.h"
+
+
+int wmain(int argc, wchar_t *argv[])
+{
+ 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);
+ for (int i = 1; i < argc; ++i) {
+ msiExecutor.arg(argv[i]);
+ }
+
+ // Install msi file.
+ return msiExecutor.execAndWaitForExit();
+
+ JP_CATCH_ALL;
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/msiwrapper/Resources.cpp Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,144 @@
+/*
+ * 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 <fstream>
+
+
+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<size_t>(name);
+ nameStr = printer.str();
+ namePtr = name;
+ } else {
+ nameStr = name;
+ namePtr = nameStr.c_str();
+ }
+ if (IS_INTRESOURCE(type)) {
+ std::wostringstream printer;
+ printer << L"#" << reinterpret_cast<size_t>(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);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jpackage/windows/native/msiwrapper/Resources.h Mon Jun 17 15:38:04 2019 -0400
@@ -0,0 +1,82 @@
+/*
+ * 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 RESOURCES_H
+#define RESOURCES_H
+
+#include "WinSysInfo.h"
+
+
+/**
+ * Classes for resource loading.
+ * Common use cases:
+ * - check if resource is available and save it to file:
+ * Resource res(_T("MyResource"), _T("CustomResourceType"));
+ * if (res.available()) {
+ * res.saveToFile(_T("c:\\temp\\my_resource.bin"));
+ * }
+ */
+
+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());
+
+ bool available() const;
+
+ // all this methods throw exception if the resource is not available
+ unsigned size() const;
+ // gets raw pointer to the resource data
+ LPCVOID rawData() const;
+
+ // save the resource to a file
+ void saveToFile(const std::wstring &filePath) const;
+
+ typedef std::vector<BYTE> ByteArray;
+ // returns the resource as byte array
+ ByteArray binary() const;
+
+private:
+ std::wstring nameStr;
+ LPCWSTR namePtr; // can be integer (MAKEINTRESOURCE) value or point to nameStr.c_str()
+ std::wstring typeStr;
+ LPCWSTR typePtr; // can be integer (MAKEINTRESOURCE) value or point to nameStr.c_str()
+ HINSTANCE instance;
+
+ void init(LPCWSTR name, LPCWSTR type, HINSTANCE module);
+
+ // generates error message
+ std::string getErrMsg(const std::string &descr) const;
+ HRSRC findResource() const;
+ LPVOID getPtr(DWORD &size) const;
+
+private:
+ // disable copying
+ Resource(const Resource&);
+ Resource& operator = (const Resource&);
+};
+
+#endif // RESOURCES_H