1 /*
   2  * Copyright (c) 2011, 2013, 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 
  26 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include <string>
  29 #include <windows.h>
  30 
  31 //#define _DEBUG
  32 
  33 #ifdef _DEBUG
  34 #include <iostream>
  35 #include <sstream>
  36 #endif
  37 
  38 using namespace std;
  39 
  40 #define MAX_KEY_LENGTH 255
  41 #define MAX_VALUE_NAME 16383
  42 
  43 bool from_string (int &result, string &str) {
  44     const char *p = str.c_str();
  45     int res = 0;
  46     for (int index = 0; ; index ++) {
  47         char c = str[index];
  48         if (c == 0  &&  index > 0) {
  49             result = res;
  50             return true;
  51         }
  52         if (c < '0'  ||  c > '9')
  53             return false;
  54         res = res * 10 + (c - '0');
  55     }
  56 }
  57 /*
  58 template <class T>
  59 bool from_string(T& t,
  60 const std::string& s,
  61 std::ios_base& (*f)(std::ios_base&)) {
  62     std::istringstream iss(s);
  63     return !(iss >> f >> t).fail();
  64 };
  65 */
  66 void PrintCSBackupAPIErrorMessage(DWORD dwErr) {
  67 
  68     char wszMsgBuff[512]; // Buffer for text.
  69 
  70     DWORD dwChars; // Number of chars returned.
  71 
  72     // Try to get the message from the system errors.
  73     dwChars = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
  74             FORMAT_MESSAGE_IGNORE_INSERTS,
  75             NULL,
  76             dwErr,
  77             0,
  78             wszMsgBuff,
  79             512,
  80             NULL);
  81 
  82     if (0 == dwChars) {
  83         // The error code did not exist in the system errors.
  84         // Try ntdsbmsg.dll for the error code.
  85 
  86         HINSTANCE hInst;
  87 
  88         // Load the library.
  89         hInst = LoadLibraryA("ntdsbmsg.dll");
  90         if (NULL == hInst) {
  91 #ifdef _DEBUG
  92             cerr << "cannot load ntdsbmsg.dll\n";
  93 #endif
  94             return;
  95 
  96         }
  97 
  98         // Try getting message text from ntdsbmsg.
  99         dwChars = FormatMessageA(FORMAT_MESSAGE_FROM_HMODULE |
 100                 FORMAT_MESSAGE_IGNORE_INSERTS,
 101                 hInst,
 102                 dwErr,
 103                 0,
 104                 wszMsgBuff,
 105                 512,
 106                 NULL);
 107 
 108         // Free the library.
 109         FreeLibrary(hInst);
 110 
 111     }
 112 
 113     // Display the error message, or generic text if not found.
 114 #ifdef _DEBUG
 115     cerr << "Error value: " << dwErr << " Message: " << ((dwChars > 0) ? wszMsgBuff : "Error message not found.") << endl;
 116 #endif
 117 
 118 }
 119 
 120 class JavaVersion {
 121 public:
 122     int v1;
 123     int v2;
 124     int v3;
 125     string home;
 126     string path;
 127 
 128     JavaVersion(int pv1, int pv2, int pv3) {
 129         v1 = pv1;
 130         v2 = pv2;
 131         v3 = pv3;
 132     }
 133 
 134     bool operator>(const JavaVersion &other) const {
 135         if (v1 > other.v1)
 136             return true;
 137         if (v1 == other.v1) {
 138             if (v2 > other.v2)
 139                 return true;
 140             if (v2 == other.v2)
 141                 return v3 > other.v3;
 142         }
 143         return false;
 144     }
 145 
 146     bool operator>=(const JavaVersion &other) const {
 147         if (v1 > other.v1)
 148             return true;
 149         if (v1 == other.v1) {
 150             if (v2 > other.v2)
 151                 return true;
 152             if (v2 == other.v2)
 153                 return v3 >= other.v3;
 154         }
 155         return false;
 156     }
 157 
 158     bool operator<(const JavaVersion &other) const {
 159         if (v1 < other.v1)
 160             return true;
 161         if (v1 == other.v1) {
 162             if (v2 < other.v2)
 163                 return true;
 164             if (v2 == other.v2)
 165                 return v3 < other.v3;
 166         }
 167         return false;
 168     }
 169 };
 170 
 171 bool checkJavaHome(HKEY key, const char * sKey, const char * jv, JavaVersion *version) {
 172     char p[MAX_KEY_LENGTH];
 173     HKEY hKey;
 174     bool result = false;
 175     int res;
 176 
 177     strcpy_s(p, MAX_KEY_LENGTH, sKey);
 178     strcat_s(p, MAX_KEY_LENGTH - strlen(p), "\\");
 179     strcat_s(p, MAX_KEY_LENGTH - strlen(p), jv);
 180 
 181     if (RegOpenKeyExA(key,
 182             p,
 183             0,
 184             KEY_READ,
 185             &hKey) == ERROR_SUCCESS
 186             ) {
 187         DWORD ot = REG_SZ;
 188         DWORD size = 255;
 189                 char data[MAX_PATH] = {0};
 190         if ((res = RegQueryValueExA(hKey, "JavaHome", NULL, &ot, (BYTE *) data, &size)) == ERROR_SUCCESS) {
 191             version->home = data;
 192             strcat_s(data, sizeof(data) - strlen(data), "\\bin\\java.exe");
 193             version->path = data;
 194             result = GetFileAttributesA(data) != 0xFFFFFFFF;
 195         } else {
 196             PrintCSBackupAPIErrorMessage(res);
 197             result = false;
 198         }
 199         RegCloseKey(hKey);
 200     } else {
 201 #ifdef _DEBUG
 202         cerr << "Can not open registry key" << endl;
 203 #endif
 204         result = false;
 205     }
 206 
 207     return result;
 208 }
 209 
 210 JavaVersion * parseName(const char * jName) {
 211     string s(jName);
 212 
 213     if (s.length() == 0) {
 214         return NULL;
 215     }
 216 
 217     string n;
 218     string::size_type pos;
 219 
 220 
 221     pos = s.find_first_of(".");
 222     if (pos != string::npos) {
 223         n = s.substr(0, pos);
 224         s = s.substr(pos + 1);
 225     } else {
 226         n = s;
 227         s = "";
 228     }
 229 
 230     int v1 = 0;
 231 
 232     if (n.length() > 0) {
 233         if (!from_string(v1, n))
 234 //        if (!from_string<int>(v1, n, std::dec))
 235             return NULL;
 236     }
 237 
 238 
 239     pos = s.find_first_of(".");
 240     if (pos != string::npos) {
 241         n = s.substr(0, pos);
 242         s = s.substr(pos + 1);
 243     } else {
 244         n = s;
 245         s = "";
 246     }
 247 
 248     int v2 = 0;
 249 
 250     if (n.length() > 0) {
 251         if (!from_string(v2, n))
 252 //        if (!from_string<int>(v2, n, std::dec))
 253             return NULL;
 254     }
 255 
 256 
 257     int nn = s.length();
 258     for (int i = 0; i < s.length(); i++) {
 259         string c = s.substr(i, 1);
 260         int tmp;
 261         if (!from_string(tmp, c)) {
 262 //        if (!from_string<int>(tmp, c, std::dec)) {
 263             nn = i;
 264             break;
 265         }
 266     }
 267 
 268     n = s.substr(0, nn);
 269     if (nn < s.length()) {
 270         s = s.substr(nn + 1);
 271     } else s = "";
 272 
 273     int v3 = 0;
 274 
 275     if (n.length() > 0) {
 276         if (!from_string(v3, n))
 277 //        if (!from_string<int>(v3, n, std::dec))
 278             v3 = 0;
 279     }
 280 
 281     int v4 = 0;
 282 
 283     //update version
 284     if (s.length() > 0) {
 285         nn = s.length();
 286         for (int i = 0; i < s.length(); i++) {
 287             string c = s.substr(i, 1);
 288             int tmp;
 289             if (!from_string(tmp, c)) {
 290 //            if (!from_string<int>(tmp, c, std::dec)) {
 291                 nn = i;
 292                 break;
 293             }
 294         }
 295 
 296         n = s.substr(0, nn);
 297 
 298         if (n.length() > 0) {
 299             if (!from_string(v4, n))
 300 //            if (!from_string<int>(v4, n, std::dec))
 301                 v4 = 0;
 302         }
 303     }
 304 
 305     return new JavaVersion(v2, v3, v4);
 306 }
 307 
 308 JavaVersion * GetMaxVersion(HKEY key, const char * sKey) {
 309     HKEY hKey;
 310     JavaVersion * result = NULL;
 311 
 312     if (RegOpenKeyExA(key,
 313             sKey,
 314             0,
 315             KEY_READ,
 316             &hKey) == ERROR_SUCCESS
 317             ) {
 318         DWORD retCode;
 319         char achClass[MAX_PATH]; // buffer for class name
 320         DWORD cchClassName = MAX_PATH; // size of class string
 321 
 322 
 323         DWORD cchValue = MAX_VALUE_NAME;
 324         DWORD cSubKeys = 0; // number of subkeys
 325         DWORD cbMaxSubKey; // longest subkey size
 326         DWORD cchMaxClass; // longest class string
 327         DWORD cValues; // number of values for key
 328         DWORD cchMaxValue; // longest value name
 329         DWORD cbMaxValueData; // longest value data
 330         DWORD cbSecurityDescriptor; // size of security descriptor
 331         FILETIME ftLastWriteTime; // last write time
 332 
 333         retCode = RegQueryInfoKeyA(
 334                 hKey, // key handle
 335                 achClass, // buffer for class name
 336                 &cchClassName, // size of class string
 337                 NULL, // reserved
 338                 &cSubKeys, // number of subkeys
 339                 &cbMaxSubKey, // longest subkey size
 340                 &cchMaxClass, // longest class string
 341                 &cValues, // number of values for this key
 342                 &cchMaxValue, // longest value name
 343                 &cbMaxValueData, // longest value data
 344                 &cbSecurityDescriptor, // security descriptor
 345                 &ftLastWriteTime); // last write time
 346 
 347         if (cSubKeys) {
 348             for (unsigned int i = 0; i < cSubKeys; i++) {
 349                 char achKey[MAX_KEY_LENGTH]; // buffer for subkey name
 350                 DWORD cbName = MAX_KEY_LENGTH;
 351                 retCode = RegEnumKeyExA(hKey, i,
 352                         achKey,
 353                         &cbName,
 354                         NULL,
 355                         NULL,
 356                         NULL,
 357                         &ftLastWriteTime);
 358 
 359                 if (retCode == ERROR_SUCCESS) {
 360 #ifdef _DEBUG
 361                     cout << achKey << endl;
 362 #endif
 363                     JavaVersion * nv = parseName(achKey);
 364 
 365                     bool isHome = checkJavaHome(key, sKey, achKey, nv);
 366 #ifdef _DEBUG
 367                     cout << nv->home << " " << isHome << endl;
 368 #endif
 369 
 370                     if (isHome)
 371                         if (result == NULL) {
 372                             result = nv;
 373 #ifdef _DEBUG
 374                             cout << "NEW" << endl;
 375 #endif
 376                         } else {
 377                             if (nv != NULL) {
 378                                 if (*nv > *result) {
 379 #ifdef _DEBUG
 380                                     cout << "REPLACE" << endl;
 381 #endif
 382                                     delete result;
 383                                     result = nv;
 384                                 } else {
 385 #ifdef _DEBUG
 386                                     cout << "NO" << endl;
 387 #endif
 388                                     delete nv;
 389                                 }
 390                             }
 391                         }
 392 
 393                 }
 394 
 395             }
 396         }
 397 
 398         RegCloseKey(hKey);
 399 
 400     }
 401 
 402     return result;
 403 }
 404 // *****************************************************************************
 405 
 406 int fileExists (const std::string& path) {
 407     WIN32_FIND_DATA ffd;
 408     HANDLE hFind;
 409 
 410     hFind = FindFirstFile (path.c_str(), &ffd);
 411     if (hFind == INVALID_HANDLE_VALUE)
 412         return FALSE;
 413 
 414     FindClose (hFind);
 415     return (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
 416 }
 417 
 418 int main(int argc, char** argv) {
 419     char buf[MAX_PATH];
 420     GetModuleFileName (NULL, buf, MAX_PATH);
 421     std::string javafxhome = buf;
 422     javafxhome.erase (javafxhome.rfind ("\\"));
 423 
 424     std::string fxlib = javafxhome + "\\..\\lib\\";
 425 
 426     const char *s = getenv ("JAVA_HOME");
 427     std::string javacmd;
 428     std::string javahome;
 429     if (s != NULL) {
 430         javahome = s;
 431         javacmd = javahome + "\\bin\\java.exe";
 432         std::string javaccmd = javahome + "\\bin\\javac.exe";
 433         if (! fileExists (javacmd.c_str ())  ||  ! fileExists (javaccmd.c_str ())) {
 434             javacmd = "";
 435             javahome = "";
 436         }
 437     } else
 438         javacmd = "";
 439 
 440     if (javacmd.length() <= 0) {
 441         //JavaVersion * jv = NULL;//GetMaxVersion(HKEY_LOCAL_MACHINE, "SOFTWARE\\JavaSoft\\Java Runtime Environment");
 442         JavaVersion * jv2 = GetMaxVersion(HKEY_LOCAL_MACHINE, "SOFTWARE\\JavaSoft\\Java Development Kit");
 443         if (jv2 != NULL) {
 444             javacmd = jv2->path;
 445             javahome = jv2->home;
 446         } else
 447             javacmd = "java.exe";
 448     }
 449 
 450     std::string cmd = "\"" + javacmd + "\"";
 451     if (javahome.length() > 0) {
 452 //        cmd += " \"-Djava.home=" + javahome + "\"";
 453         SetEnvironmentVariable ("JAVA_HOME", javahome.c_str ());
 454     }
 455     cmd += " -Xmx256M \"-Djavafx.home=" + javafxhome
 456             + "\" -classpath \"" + fxlib + "ant-javafx.jar;"
 457             + "\" com.sun.javafx.tools.packager.Main";
 458 
 459     for (int i = 1; i < argc; i ++) {
 460         cmd = cmd + " \"" + argv[i] + "\"";
 461     }
 462 
 463 #ifdef _DEBUG
 464     printf ("%s", cmd.c_str());
 465 #endif
 466 
 467     STARTUPINFO start;
 468     PROCESS_INFORMATION pi;
 469     memset (&start, 0, sizeof (start));
 470     start.cb = sizeof (start);
 471 
 472     if (! CreateProcess (NULL, (char *) cmd.c_str (),
 473             NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, NULL, &start, &pi)) {
 474 #ifdef _DEBUG
 475         fprintf (stderr, "CAnnot start java.exe");
 476 #endif
 477         return EXIT_FAILURE;
 478     }
 479 
 480     WaitForSingleObject (pi.hProcess, INFINITE);
 481     unsigned long exitCode;
 482     GetExitCodeProcess (pi.hProcess, &exitCode);
 483 
 484     CloseHandle (pi.hProcess);
 485     CloseHandle (pi.hThread);
 486 
 487     return exitCode;
 488 }