blob: fee1f221e9e793c9ba553d21ad108e99d8cae042 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <windows.h>
#include <wchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <shellapi.h>
#include "FileUtils.h"
#include "StringUtils.h"
#include "JavaUtils.h"
#include "RegistryUtils.h"
#include "Launcher.h"
#include "ProcessUtils.h"
#include "StringUtils.h"
#include "ExtractUtils.h"
#include "Main.h"
#include "shlobj.h"
const DWORD NUMBER_OF_HELP_ARGUMENTS = 11;
const DWORD READ_WRITE_BUFSIZE = 65536;
const WCHAR * outputFileArg = L"--output";
const WCHAR * javaArg = L"--javahome";
const WCHAR * debugArg = L"--verbose";
const WCHAR * tempdirArg = L"--tempdir";
const WCHAR * classPathPrepend = L"--classpath-prepend";
const WCHAR * classPathAppend = L"--classpath-append";
const WCHAR * extractArg = L"--extract";
const WCHAR * helpArg = L"--help";
const WCHAR * helpOtherArg = L"/?";
const WCHAR * silentArg = L"--silent";
const WCHAR * nospaceCheckArg = L"--nospacecheck";
const WCHAR * localeArg = L"--locale";
const WCHAR * javaParameterPrefix = L"-J";
const WCHAR * NEW_LINE = L"\n";
const WCHAR * CLASSPATH_SEPARATOR = L";";
const WCHAR * CLASS_SUFFIX = L".class";
DWORD isLauncherArgument(LauncherProperties * props, WCHAR * value) {
DWORD i=0;
for(i=0;i<props->launcherCommandArguments->size;i++) {
if(lstrcmpW(props->launcherCommandArguments->items[i], value)==0) {
return 1;
}
}
return 0;
}
DWORD getArgumentIndex(LauncherProperties * props, const WCHAR *arg, DWORD removeArgument) {
WCHARList *cmd = props->commandLine;
DWORD i=0;
for(i=0;i<cmd->size;i++) {
if(cmd->items[i]!=NULL) { // argument has not been cleaned yet
if(lstrcmpW(arg, cmd->items[i])==0) { //argument is the same as the desired
if(removeArgument) FREE(cmd->items[i]); // free it .. we don`t need it anymore
return i;
}
}
}
return cmd->size;
}
DWORD argumentExists(LauncherProperties * props, const WCHAR *arg, DWORD removeArgument) {
DWORD index = getArgumentIndex(props, arg, removeArgument);
return (index < props->commandLine->size);
}
WCHAR * getArgumentValue(LauncherProperties * props, const WCHAR *arg, DWORD removeArgument, DWORD mandatory) {
WCHARList *cmd = props->commandLine;
WCHAR * result = NULL;
DWORD i = getArgumentIndex(props, arg, removeArgument);
if((i+1) < cmd->size) {
//we have at least one more argument
if(mandatory || !isLauncherArgument(props, cmd->items[i+1])) {
result = appendStringW(NULL, cmd->items[i+1]);
if(removeArgument) FREE(cmd->items[i+1]);
}
}
return result;
}
void setOutputFile(LauncherProperties * props, WCHAR *path) {
HANDLE out = INVALID_HANDLE_VALUE ;
out = CreateFileW(path, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, 0, 0);
if(out!=INVALID_HANDLE_VALUE) {
SetStdHandle(STD_OUTPUT_HANDLE, out);
SetStdHandle(STD_ERROR_HANDLE, out);
props->stdoutHandle = out;
props->stderrHandle = out;
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "[CMD Argument] Redirect output to file : ", 0);
writeMessageW(props, OUTPUT_LEVEL_DEBUG, 0, path, 1);
} else {
WCHAR * err = NULL;
DWORD code = GetLastError();
props->status = ERROR_INPUTOUPUT;
writeErrorA(props, OUTPUT_LEVEL_DEBUG, 1, "[CMD Argument] Can`t create file: ", path, code);
err = getErrorDescription(code);
showMessageW(props, L"Can`t redirect output to file!\n\nRequested file : %s\n%s", 2, path, err);
FREE(err);
}
}
void setOutput(LauncherProperties * props) {
WCHAR * file = props->userDefinedOutput;
if(file!=NULL) {
DWORD exists = fileExists(file);
if((exists && !isDirectory(file) )|| !exists) {
setOutputFile(props, file);
}
}
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 0,
(props->outputLevel == OUTPUT_LEVEL_DEBUG) ?
"[CMD Argument] Using debug output." :
"Using normal output." , 1);
}
void loadLocalizationStrings(LauncherProperties *props) {
// load localized messages
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "Loading I18N Strings.", 1);
loadI18NStrings(props);
if(!isOK(props)) {
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 1, "Error! Can`t load i18n strings!!", 1);
showErrorW(props, INTEGRITY_ERROR_PROP, 1, props->exeName);
}
}
void readDefaultRoots(LauncherProperties *props) {
TCHAR appDataValueTChar[MAX_PATH];
TCHAR localAppDataValueTChar[MAX_PATH];
SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, appDataValueTChar);
SHGetFolderPath(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, localAppDataValueTChar);
WCHAR* appDataValue = toWCHAR(appDataValueTChar);
WCHAR* localAppDataValue = toWCHAR(localAppDataValueTChar);
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "Reading Default Userdir and Cachedir roots...", 1);
props->defaultUserDirRoot = appendStringW(appDataValue, toWCHAR("\\NetBeans"));
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "defaultUserDirRoot: ", 0);
writeMessageW(props, OUTPUT_LEVEL_DEBUG, 0, props->defaultUserDirRoot, 1);
props->defaultCacheDirRoot = appendStringW(localAppDataValue, toWCHAR("\\NetBeans\\Cache"));
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "defaultCacheDirRoot: ", 0);
writeMessageW(props, OUTPUT_LEVEL_DEBUG, 0, props->defaultCacheDirRoot, 1);
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "End of Reading Default Roots.", 1);
}
void createTMPDir(LauncherProperties * props) {
WCHAR * argTempDir = NULL;
DWORD createRndSubDir = 1;
if((argTempDir = props->userDefinedExtractDir) !=NULL) {
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 1, "[CMD Argument] Extract data to directory: ", 0);
writeMessageW(props, OUTPUT_LEVEL_DEBUG, 1, argTempDir, 1);
createRndSubDir = 0;
} else if((argTempDir = props->userDefinedTempDir) !=NULL) {
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 0, "[CMD Argument] Using tmp directory: ", 0);
writeMessageW(props, OUTPUT_LEVEL_NORMAL, 0, argTempDir, 1);
}
createTempDirectory(props, argTempDir, createRndSubDir);
if(!isOK(props)) {
showErrorW(props, CANT_CREATE_TEMP_DIR_PROP, 1, props->tmpDir);
}
}
void checkExtractionStatus(LauncherProperties *props) {
if(props->status == ERROR_FREESPACE) {
DWORD hiMB = props->bundledSize->High;
DWORD lowMB = props->bundledSize->Low;
DWORD hiMult = (hiMB!=0) ? ((MAXDWORD / 1024) + 1) / 1024 : 0;
DWORD dw = hiMult * hiMB + lowMB / (1024 * 1024) + 1;
WCHAR * size = DWORDtoWCHAR(dw);
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 1, "Error! Not enought free space !", 1);
showErrorW(props, NOT_ENOUGH_FREE_SPACE_PROP, 2, size, tempdirArg);
FREE(size);
}
else if(props->status == ERROR_INTEGRITY) {
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 1, "Error! Can`t extract data from bundle. Seems to be integrirty error!", 1);
showErrorW(props, INTEGRITY_ERROR_PROP, 1, props->exeName);
}
}
void trySetCompatibleJava(WCHAR * location, LauncherProperties * props) {
if(isTerminated(props)) return;
if(location!=NULL) {
JavaProperties * javaProps = NULL;
if(inList(props->alreadyCheckedJava, location)) {
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 0, "... already checked location ", 0);
writeMessageW(props, OUTPUT_LEVEL_NORMAL, 0, location, 1);
// return here and don`t proceed with private jre checking since it`s already checked as well
return;
} else {
props->alreadyCheckedJava = addStringToList(props->alreadyCheckedJava, location);
}
getJavaProperties(location, props, &javaProps);
if(isOK(props)) {
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 0, "... some java at ", 0);
writeMessageW(props, OUTPUT_LEVEL_NORMAL, 0, location, 1);
// some java there, check compatibility
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 0, "... checking compatibility of java : ", 0);
writeMessageW(props, OUTPUT_LEVEL_NORMAL, 0, javaProps->javaHome, 1);
if(isJavaCompatible(javaProps, props->compatibleJava, props->compatibleJavaNumber)) {
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 0, "... compatible", 1);
props->java = javaProps;
} else {
props->status = ERROR_JVM_UNCOMPATIBLE;
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 0, "... uncompatible", 1);
freeJavaProperties(&javaProps);
}
} else {
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 0, "... no java at ", 0);
writeMessageW(props, OUTPUT_LEVEL_NORMAL, 0, location, 1);
if (props->status==ERROR_INPUTOUPUT) {
props->status = ERROR_JVM_NOT_FOUND;
}
}
if(props->status == ERROR_JVM_NOT_FOUND) { // check private JRE
//DWORD privateJreStatus = props->status;
WCHAR * privateJre = appendStringW(NULL, location);
privateJre = appendStringW(privateJre, L"\\jre");
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 0, "... check private jre at ", 0);
writeMessageW(props, OUTPUT_LEVEL_NORMAL, 0, privateJre, 1);
if(inList(props->alreadyCheckedJava, privateJre)) {
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 0, "... already checked location ", 0);
writeMessageW(props, OUTPUT_LEVEL_NORMAL, 0, privateJre, 1);
} else {
props->alreadyCheckedJava = addStringToList(props->alreadyCheckedJava, privateJre);
getJavaProperties(privateJre, props, &javaProps);
if(isOK(props)) {
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 0, "... checking compatibility of private jre : ", 0);
writeMessageW(props, OUTPUT_LEVEL_NORMAL, 0, javaProps->javaHome, 1);
if(isJavaCompatible(javaProps, props->compatibleJava, props->compatibleJavaNumber)) {
props->java = javaProps;
props->status = ERROR_OK;
} else {
freeJavaProperties(&javaProps);
props->status = ERROR_JVM_UNCOMPATIBLE;
}
} else if (props->status==ERROR_INPUTOUPUT) {
props->status = ERROR_JVM_NOT_FOUND;
}
}
FREE(privateJre);
}
} else {
props->status = ERROR_JVM_NOT_FOUND;
}
}
void resolveTestJVM(LauncherProperties * props) {
WCHAR * testJVMFile = NULL;
WCHAR * testJVMClassPath = NULL;
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "Resolving testJVM classpath...", 1);
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... first step : ", 0);
writeMessageW(props, OUTPUT_LEVEL_DEBUG, 0, props->testJVMFile->path, 1);
resolvePath(props, props->testJVMFile);
testJVMFile = props->testJVMFile->resolved;
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... second : ", 0);
writeMessageW(props, OUTPUT_LEVEL_DEBUG, 0, props->testJVMFile->resolved, 1);
if(isDirectory(testJVMFile)) { // the directory of the class file is set
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... testJVM is : directory ", 1);
testJVMClassPath = appendStringW(NULL, testJVMFile);
} else { // testJVMFile is either .class file or .jar/.zip file with the neccessary class file
WCHAR * dir = getParentDirectory(testJVMFile);
WCHAR * ptr = testJVMFile;
do {
ptr = searchW(ptr, CLASS_SUFFIX); // check if ptr contains .class
if(ptr==NULL) { // .jar or .zip file
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... testJVM is : ZIP/JAR file", 1);
testJVMClassPath = appendStringW(NULL, testJVMFile);
break;
}
ptr += getLengthW(CLASS_SUFFIX); // shift to the right after the ".class"
if(ptr==NULL || getLengthW(ptr)==0) { // .class was at the end of the ptr
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... testJVM is : .class file ", 1);
testJVMClassPath = appendStringW(NULL, dir);
break;
}
} while(1);
FREE(dir);
}
FREE(props->testJVMFile->resolved);
props->testJVMFile->resolved = testJVMClassPath;
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... resolved : ", 0);
writeMessageW(props, OUTPUT_LEVEL_DEBUG, 0, props->testJVMFile->resolved, 1);
}
void findSuitableJava(LauncherProperties * props) {
if(!isOK(props)) return;
//resolve testJVM file
resolveTestJVM(props);
if(!fileExists(props->testJVMFile->resolved)) {
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 1, "Can`t find TestJVM classpath : ", 0);
writeMessageW(props, OUTPUT_LEVEL_NORMAL, 1, props->testJVMFile->resolved, 1);
showErrorW(props, JVM_NOT_FOUND_PROP, 1, javaArg);
props->status = ERROR_JVM_NOT_FOUND;
return;
} else if(!isTerminated(props)) {
// try to get java location from command line arguments
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 0, "", 1);
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 0, "Finding JAVA...", 1);
//WCHAR * java = NULL;
if(props->userDefinedJavaHome!=NULL) { // using user-defined JVM via command-line parameter
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 0, "[CMD Argument] Try to use java from ", 0);
writeMessageW(props, OUTPUT_LEVEL_NORMAL, 0, props->userDefinedJavaHome, 1);
trySetCompatibleJava(props->userDefinedJavaHome, props);
if( props->status == ERROR_JVM_NOT_FOUND || props->status == ERROR_JVM_UNCOMPATIBLE) {
const char * prop = (props->status == ERROR_JVM_NOT_FOUND) ?
JVM_USER_DEFINED_ERROR_PROP :
JVM_UNSUPPORTED_VERSION_PROP;
showErrorW(props, prop, 1, props->userDefinedJavaHome);
}
} else { // no user-specified java argument
findSystemJava(props);
if( props->java ==NULL) {
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 1, "... no java was found", 1);
if(props->status == ERROR_BUNDLED_JVM_EXTRACTION) {
showErrorW(props, BUNDLED_JVM_EXTRACT_ERROR_PROP, 1, javaArg);
} else if(props->status == ERROR_BUNDLED_JVM_VERIFICATION) {
showErrorW(props, BUNDLED_JVM_VERIFY_ERROR_PROP, 1, javaArg);
} else {
showErrorW(props, JVM_NOT_FOUND_PROP, 1, javaArg);
props->status = ERROR_JVM_NOT_FOUND;
}
}
}
if(props->java!=NULL) {
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 1, "Compatible jvm was found on the system", 1);
printJavaProperties(props, props->java);
} else {
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 1, "No compatible jvm was found on the system", 1);
}
}
return;
}
void resolveLauncherStringProperty(LauncherProperties * props, WCHAR ** result) {
if(*result!=NULL) {
WCHAR * propStart = searchW(*result, L"$P{");
if(propStart!=NULL) {
WCHAR * propEnd = searchW(propStart + 3, L"}");
if(propEnd!=NULL) {
WCHAR * propName;
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... resolving string property", 1);
propName = appendStringNW(NULL, 0, propStart + 3 ,
getLengthW(propStart + 3) - getLengthW(propEnd));
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... property name is : ", 0);
writeMessageW(props, OUTPUT_LEVEL_DEBUG, 0, propName, 1);
if(propName!=NULL) {
char * name = toChar(propName);
const WCHAR * propValue = getI18nProperty(props, name);
if(propValue!=NULL) {
WCHAR * tmp = appendStringNW(NULL, 0, *result, getLengthW(*result) - getLengthW(propStart));
tmp = appendStringW(tmp, propValue);
tmp = appendStringW(tmp, propEnd + 1);
FREE(*result);
*result = tmp;
}
FREE(name);
FREE(propName);
}
}
}
}
}
void resolveLauncherProperties(LauncherProperties * props, WCHAR **result) {
if(*result != NULL) {
WCHAR * propStart = searchW(*result, L"$L{");
if(propStart!=NULL) {
WCHAR * propEnd = searchW(propStart + 3, L"}");
if(propEnd!=NULL) {
WCHAR * propName = appendStringNW(NULL, 0, propStart + 3 , getLengthW(propStart + 3) - getLengthW(propEnd));
if(propName!=NULL) {
WCHAR * propValue = NULL;
if(lstrcmpW(propName, L"nbi.launcher.tmp.dir")==0) {
propValue = appendStringW(NULL, props->tmpDir); // launcher tmpdir
} else if(lstrcmpW(propName, L"nbi.launcher.java.home")==0) {
if(props->java!=NULL) {
propValue = appendStringW(NULL, props->java->javaHome); // relative to javahome
}
} else if(lstrcmpW(propName, L"nbi.launcher.user.home")==0) {
propValue = getCurrentUserHome();
} else if(lstrcmpW(propName, L"nbi.launcher.parent.dir")==0) {
propValue = appendStringW(NULL, props->exeDir); // launcher parent
}
if(propValue!=NULL) {
WCHAR * tmp = appendStringNW(NULL, 0, *result, getLengthW(*result) - getLengthW(propStart));
tmp = appendStringW(tmp, propValue);
tmp = appendStringW(tmp, propEnd + 1);
FREE(*result);
FREE(propValue);
*result = tmp;
}
}
}
}
}
}
void resolveString(LauncherProperties * props, WCHAR ** result) {
WCHAR * tmp = NULL;
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "Resolving string : ", 0);
writeMessageW(props, OUTPUT_LEVEL_DEBUG, 0, *result, 1);
do {
FREE(tmp);
tmp = appendStringW(NULL, *result);
//writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... step 1 : ", 0);
//writeMessageW(props, OUTPUT_LEVEL_DEBUG, 0, *result, 1);
resolveLauncherProperties(props, result);
//writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... step 2 : ", 0);
//writeMessageW(props, OUTPUT_LEVEL_DEBUG, 0, *result, 1);
resolveLauncherStringProperty(props, result);
//writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... step 3 : ", 0);
//writeMessageW(props, OUTPUT_LEVEL_DEBUG, 0, *result, 1);
} while(lstrcmpW(tmp, *result)!=0);
FREE(tmp);
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, ".... resolved : ", 0);
writeMessageW(props, OUTPUT_LEVEL_DEBUG, 0, *result, 1);
}
void resolvePath(LauncherProperties * props, LauncherResource * file) {
DWORD i;
if(file==NULL) return;
if(file->resolved!=NULL) return;
file->resolved = appendStringW(NULL, file->path);
resolveString(props, & (file->resolved));
for(i=0;i<getLengthW(file->resolved);i++) {
if(file->resolved[i]==L'/') {
file->resolved[i]=L'\\';
}
}
}
void setClasspathElements(LauncherProperties * props) {
if(isOK(props)) {
WCHAR * preCP = NULL;
WCHAR * appCP = NULL;
WCHAR *tmp = NULL;
DWORD i = 0 ;
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "Modifying classpath ...", 1);
// add some libraries to the beginning of the classpath
while((preCP = getArgumentValue(props, classPathPrepend, 1, 1))!=NULL) {
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... adding entry to the beginning of classpath : ", 0);
writeMessageW(props, OUTPUT_LEVEL_DEBUG, 0, preCP, 1);
if (props->classpath != NULL) {
preCP = appendStringW(preCP, CLASSPATH_SEPARATOR);
}
//WCHAR *last = props->classpath;
resolveString(props, &preCP);
tmp = appendStringW(preCP, props->classpath);
FREE(props->classpath);
props->classpath = tmp;
}
for(i=0;i<props->jars->size;i++) {
WCHAR * resolvedCpEntry = NULL;
resolvePath(props, props->jars->items[i]);
resolvedCpEntry = props->jars->items[i]->resolved;
if(!fileExists(resolvedCpEntry)) {
props->status = EXTERNAL_RESOURCE_MISSING;
showErrorW(props, EXTERNAL_RESOURE_LACK_PROP, 1, resolvedCpEntry);
return;
}
if (props->classpath != NULL) {
props->classpath = appendStringW(props->classpath, CLASSPATH_SEPARATOR);
}
props->classpath = appendStringW(props->classpath, resolvedCpEntry);
}
// add some libraries to the end of the classpath
while((appCP = getArgumentValue(props, classPathAppend, 1, 1))!=NULL) {
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... adding entry to the end of classpath : ", 0);
writeMessageW(props, OUTPUT_LEVEL_DEBUG, 0, appCP, 1);
if (props->classpath != NULL) {
props->classpath = appendStringW(props->classpath, CLASSPATH_SEPARATOR);
}
resolveString(props, &appCP);
props->classpath = appendStringW(props->classpath, appCP);
FREE(appCP);
}
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... finished", 1);
}
}
void setAdditionalArguments(LauncherProperties * props) {
if(isOK(props)) {
WCHARList * cmd = props->commandLine;
WCHAR ** javaArgs;
WCHAR ** appArgs;
DWORD i=0;
DWORD jArg = 0; // java arguments number
DWORD aArg = 0; // app arguments number
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0,
"Parsing rest of command line arguments to add them to java or application parameters... ", 1);
// get number for array creation
for(i=0;i<cmd->size;i++) {
if(cmd->items[i]!=NULL) {
if(searchW(cmd->items[i], javaParameterPrefix)!=NULL) {
jArg++;
} else {
aArg++;
}
}
}
// handle DefaultUserDirRoot, DefaultCacheDirRoot - increasing array size
jArg = jArg + 2;
//fill the array
if(jArg>0) {
int size = jArg + props->jvmArguments->size;
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, DWORDtoCHAR(size), 1);
javaArgs = newppWCHAR(jArg + props->jvmArguments->size);
for (i=0;i<props->jvmArguments->size;i++) {
javaArgs[i] = props->jvmArguments->items[i];
}
FREE(props->jvmArguments->items);
// cont. handle DefaultUserDirRoot, DefaultCacheDirRoot
// * add -Dnetbeans.default_userdir_root
// * add -Dnetbeans.default_cachedir_root
javaArgs[i-2] = appendStringW(toWCHAR("-Dnetbeans.default_userdir_root="), props->defaultUserDirRoot);
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "Added an JVM argument: ", 0);
writeMessageW(props, OUTPUT_LEVEL_DEBUG, 0, javaArgs[i-2], 1);
javaArgs[i-1] = appendStringW(toWCHAR("-Dnetbeans.default_cachedir_root="), props->defaultCacheDirRoot);
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "Added an JVM argument: ", 0);
writeMessageW(props, OUTPUT_LEVEL_DEBUG, 0, javaArgs[i-1], 1);
} else {
javaArgs = NULL;
}
if(aArg>0) {
appArgs = newppWCHAR(aArg + props->appArguments->size);
for (i=0; i < props->appArguments->size; i++) {
appArgs [i]= props->appArguments->items[i];
}
FREE(props->appArguments->items);
} else {
appArgs = NULL;
}
jArg = aArg = 0;
for(i=0;i<cmd->size;i++) {
if(cmd->items[i]!=NULL) {
if(searchW(cmd->items[i], javaParameterPrefix)!=NULL) {
javaArgs [ props->jvmArguments->size + jArg] = appendStringW(NULL, cmd->items[i] + getLengthW(javaParameterPrefix));
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... adding JVM argument : ", 0);
writeMessageW(props, OUTPUT_LEVEL_DEBUG, 0, javaArgs [ props->jvmArguments->size + jArg], 1);
jArg ++ ;
} else {
appArgs [ props->appArguments->size + aArg] = appendStringW(NULL, cmd->items[i]);
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... adding APP argument : ", 0);
writeMessageW(props, OUTPUT_LEVEL_DEBUG, 0, appArgs [ props->appArguments->size + aArg], 1);
aArg++;
}
FREE(cmd->items[i]);
}
}
props->appArguments->size = props->appArguments->size + aArg;
props->jvmArguments->size = props->jvmArguments->size + jArg;
if(props->jvmArguments->items==NULL) props->jvmArguments->items = javaArgs;
if(props->appArguments->items==NULL) props->appArguments->items = appArgs;
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... resolving jvm arguments", 1);
for(i=0;i<props->jvmArguments->size;i++) {
resolveString(props, &props->jvmArguments->items[i]);
}
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... resolving app arguments", 1);
for(i=0;i<props->appArguments->size;i++) {
resolveString(props, &props->appArguments->items[i]);
}
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... finished parsing parameters", 1);
}
}
void appendCommandLineArgument( WCHAR ** command, const WCHAR * arg) {
WCHAR * escapedString = escapeString(arg);
*command = appendStringW(*command, escapedString);
FREE(escapedString);
*command = appendStringW(*command, L" ");
}
void setLauncherCommand(LauncherProperties *props) {
if(!isOK(props)) return;
if(props->java==NULL) {
props->status = ERROR_JVM_NOT_FOUND;
return;
} else {
WCHAR * command = NULL;
WCHAR * javaIOTmpdir = NULL;
DWORD i = 0;
appendCommandLineArgument(&command, props->java->javaExe);
command = appendStringW(command, L"-Djava.io.tmpdir=");
javaIOTmpdir = getParentDirectory(props->tmpDir);
appendCommandLineArgument(&command, javaIOTmpdir);
FREE(javaIOTmpdir);
for(i=0;i<props->jvmArguments->size;i++) {
appendCommandLineArgument(&command, props->jvmArguments->items[i]);
}
appendCommandLineArgument(&command, L"-classpath");
appendCommandLineArgument(&command, props->classpath);
appendCommandLineArgument(&command, props->mainClass);
for(i=0;i<props->appArguments->size; i++) {
appendCommandLineArgument(&command, props->appArguments->items[i]);
}
props->command = command;
}
}
void executeMainClass(LauncherProperties * props) {
if(isOK(props) && !isTerminated(props)) {
int64t * minSize = newint64_t(0, 0);
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 0, "Executing main class", 1);
checkFreeSpace(props, props->tmpDir, minSize);
if(isOK(props)) {
HANDLE hErrorRead;
HANDLE hErrorWrite;
char * error = NULL;
CreatePipe(&hErrorRead, &hErrorWrite, NULL, 0);
hideLauncherWindows(props);
executeCommand(props, props->command, NULL, INFINITE, props->stdoutHandle, hErrorWrite, NORMAL_PRIORITY_CLASS);
if(!isOK(props)) {
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... an error occured during JVM running main class", 1);
props->exitCode = props->status;
} else {
char * s = DWORDtoCHAR(props->exitCode);
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... main class has finished its work. Exit code is ", 0);
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, s, 1);
FREE(s);
}
error = readHandle(hErrorRead);
if(getLengthA(error)>1) {
DWORD showMessage = 0;
char * ptr = error;
while(ptr!=NULL) {
//Bug #105165 and #194242
if((searchA(ptr, "Picked up ") == NULL && searchA(ptr, "fatal: Not a git repository") == NULL) && getLengthA(ptr) > 1) {
showMessage = 1;
break;
}
ptr = searchA(ptr, "\n");
if(ptr!=NULL) ptr++;
}
if(showMessage && props->exitCode != 0) {
WCHAR * errorW = toWCHAR(error);
showMessageW(props, getI18nProperty(props, JAVA_PROCESS_ERROR_PROP), 1, errorW);
FREE(errorW);
} else {
writeMessageA(props, OUTPUT_LEVEL_NORMAL, 1, error, 1);
}
}
CloseHandle(hErrorWrite);
CloseHandle(hErrorRead);
FREE(error);
Sleep(1);
} else {
props->status = ERROR_FREESPACE;
props->exitCode = props->status;
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 1, "... there is not enough space in tmp dir to execute main jar", 1);
}
FREE(minSize);
}
}
DWORD isOnlyHelp(LauncherProperties * props) {
if(argumentExists(props, helpArg, 1) || argumentExists(props, helpOtherArg, 1)) {
WCHARList * help = newWCHARList(NUMBER_OF_HELP_ARGUMENTS);
DWORD counter = 0;
WCHAR * helpString = NULL;
help->items[counter++] = formatMessageW(getI18nProperty(props, ARG_JAVA_PROP), 1, javaArg);
help->items[counter++] = formatMessageW(getI18nProperty(props, ARG_TMP_PROP), 1, tempdirArg);
help->items[counter++] = formatMessageW(getI18nProperty(props, ARG_EXTRACT_PROP), 1, extractArg);
help->items[counter++] = formatMessageW(getI18nProperty(props, ARG_OUTPUT_PROPERTY), 1, outputFileArg);
help->items[counter++] = formatMessageW(getI18nProperty(props, ARG_DEBUG_PROP), 1, debugArg);
help->items[counter++] = formatMessageW(getI18nProperty(props, ARG_CPA_PROP), 1, classPathAppend);
help->items[counter++] = formatMessageW(getI18nProperty(props, ARG_CPP_PROP), 1, classPathPrepend);
help->items[counter++] = formatMessageW(getI18nProperty(props, ARG_DISABLE_SPACE_CHECK), 1, nospaceCheckArg);
help->items[counter++] = formatMessageW(getI18nProperty(props, ARG_LOCALE_PROP), 1, localeArg);
help->items[counter++] = formatMessageW(getI18nProperty(props, ARG_SILENT_PROP), 1, silentArg);
help->items[counter++] = formatMessageW(getI18nProperty(props, ARG_HELP_PROP), 1, helpArg);
for(counter=0;counter<NUMBER_OF_HELP_ARGUMENTS;counter++) {
helpString = appendStringW(appendStringW(helpString, help->items[counter]), NEW_LINE);
}
freeWCHARList(&help);
showMessageW(props, helpString, 0);
FREE(helpString);
return 1;
}
return 0;
}
DWORD isSilent(LauncherProperties * props) {
return props->silentMode;
}
WCHARList * getCommandlineArguments() {
int argumentsNumber = 0;
int i=0;
WCHAR ** commandLine = CommandLineToArgvW(GetCommandLineW(), &argumentsNumber);
// the first is always the running program.. we don`t need it
// it is that same as GetModuleFileNameW says
WCHARList * commandsList = newWCHARList((DWORD) (argumentsNumber - 1) );
for(i=0;i<argumentsNumber - 1;i++) {
commandsList->items[i] = appendStringW(NULL, commandLine[i + 1]);
}
LocalFree(commandLine);
return commandsList;
}
LauncherProperties * createLauncherProperties() {
LauncherProperties *props = (LauncherProperties*)LocalAlloc(LPTR, sizeof(LauncherProperties));
DWORD c = 0;
props->launcherCommandArguments = newWCHARList(11);
props->launcherCommandArguments->items[c++] = appendStringW(NULL, outputFileArg);
props->launcherCommandArguments->items[c++] = appendStringW(NULL, javaArg);
props->launcherCommandArguments->items[c++] = appendStringW(NULL, debugArg);
props->launcherCommandArguments->items[c++] = appendStringW(NULL, tempdirArg);
props->launcherCommandArguments->items[c++] = appendStringW(NULL, classPathPrepend);
props->launcherCommandArguments->items[c++] = appendStringW(NULL, classPathAppend);
props->launcherCommandArguments->items[c++] = appendStringW(NULL, extractArg);
props->launcherCommandArguments->items[c++] = appendStringW(NULL, helpArg);
props->launcherCommandArguments->items[c++] = appendStringW(NULL, helpOtherArg);
props->launcherCommandArguments->items[c++] = appendStringW(NULL, silentArg);
props->launcherCommandArguments->items[c++] = appendStringW(NULL, nospaceCheckArg);
props->jvmArguments = NULL;
props->appArguments = NULL;
props->extractOnly = 0;
props->mainClass = NULL;
props->testJVMClass = NULL;
props->classpath = NULL;
props->jars = NULL;
props->testJVMFile = NULL;
props->tmpDir = NULL;
props->tmpDirCreated = 0;
props->compatibleJava=NULL;
props->compatibleJavaNumber=0;
props->java = NULL;
props->command = NULL;
props->jvms = NULL;
props->other = NULL;
props->alreadyCheckedJava = NULL;
props->exePath = getExePath();
props->exeName = getExeName();
props->exeDir = getExeDirectory();
props->handler = CreateFileW(props->exePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
props->bundledSize = newint64_t(0, 0);
props->bundledNumber = 0;
props->commandLine = getCommandlineArguments();
props->status = ERROR_OK;
props->exitCode = 0;
props->outputLevel = argumentExists(props, debugArg, 1) ? OUTPUT_LEVEL_DEBUG : OUTPUT_LEVEL_NORMAL;
props->stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE);
props->stderrHandle = GetStdHandle(STD_ERROR_HANDLE);
props->bufsize = READ_WRITE_BUFSIZE;
props->restOfBytes = createSizedString();
props->I18N_PROPERTIES_NUMBER = 0;
props->i18nMessages = NULL;
props->userDefinedJavaHome = getArgumentValue(props, javaArg, 1, 1);
props->userDefinedTempDir = getArgumentValue(props, tempdirArg, 1, 1);
props->userDefinedLocale = getArgumentValue(props, localeArg, 0, 1);
props->userDefinedExtractDir = NULL;
props->extractOnly = 0;
if(argumentExists(props, extractArg, 0)) {
props->userDefinedExtractDir = getArgumentValue(props, extractArg, 1, 0);
if(props->userDefinedExtractDir==NULL) {// next argument is null or another launcher argument
props->userDefinedExtractDir = getCurrentDirectory();
}
props->extractOnly = 1;
}
props->userDefinedOutput = getArgumentValue(props, outputFileArg, 1, 1);
props->checkForFreeSpace = !argumentExists(props, nospaceCheckArg, 0);
props->silentMode = argumentExists(props, silentArg, 0);
props->launcherSize = getFileSize(props->exePath);
props->isOnlyStub = (compare(props->launcherSize, STUB_FILL_SIZE) < 0);
return props;
}
void freeLauncherResourceList(LauncherResourceList ** list) {
if(*list!=NULL) {
if((*list)->items!=NULL) {
DWORD i=0;
for(i=0;i<(*list)->size;i++) {
freeLauncherResource(&((*list)->items[i]));
}
FREE((*list)->items);
}
FREE((*list));
}
}
void freeLauncherProperties(LauncherProperties **props) {
if((*props)!=NULL) {
DWORD i=0;
writeMessageA(*props, OUTPUT_LEVEL_DEBUG, 0, "Closing launcher properties", 1);
freeWCHARList(& ( (*props)->appArguments));
freeWCHARList(& ( (*props)->jvmArguments));
FREE((*props)->mainClass);
FREE((*props)->testJVMClass);
FREE((*props)->classpath);
freeLauncherResourceList(&((*props)->jars));
freeLauncherResourceList(&((*props)->jvms));
freeLauncherResourceList(&((*props)->other));
freeLauncherResource(&((*props)->testJVMFile));
FREE((*props)->tmpDir);
for(i=0;i<(*props)->compatibleJavaNumber;i++) {
JavaCompatible * jc = (*props)->compatibleJava[i];
if(jc!=NULL) {
FREE(jc->minVersion);
FREE(jc->maxVersion);
FREE(jc->vendor);
FREE(jc->osName);
FREE(jc->osArch);
FREE((*props)->compatibleJava[i]);
}
}
freeStringList(&((*props)->alreadyCheckedJava));
FREE((*props)->compatibleJava);
freeJavaProperties(&((*props)->java));
FREE((*props)->userDefinedJavaHome);
FREE((*props)->userDefinedTempDir);
FREE((*props)->userDefinedExtractDir);
FREE((*props)->userDefinedOutput);
FREE((*props)->userDefinedLocale);
FREE((*props)->command);
FREE((*props)->exePath);
FREE((*props)->exeDir);
FREE((*props)->exeName);
FREE((*props)->bundledSize);
FREE((*props)->launcherSize);
freeSizedString(&((*props)->restOfBytes));
flushHandle((*props)->stdoutHandle);
flushHandle((*props)->stderrHandle);
CloseHandle((*props)->stdoutHandle);
CloseHandle((*props)->stderrHandle);
freeI18NMessages((*props));
freeWCHARList(& ((*props)->launcherCommandArguments));
freeWCHARList(& ((*props)->commandLine));
CloseHandle((*props)->handler);
FREE((*props));
}
return;
}
void printStatus(LauncherProperties * props) {
char * s = DWORDtoCHAR(props->status);
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... EXIT status : ", 0);
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, s, 1);
FREE(s);
s = DWORDtoCHAR(props->exitCode);
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... EXIT code : ", 0);
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, s, 1);
FREE(s);
}
void processLauncher(LauncherProperties * props) {
setOutput(props);
if(!isOK(props) || isTerminated(props)) return;
setProgressRange(props, props->launcherSize);
if(!isOK(props) || isTerminated(props)) return;
skipStub(props);
if(!isOK(props) || isTerminated(props)) return;
readDefaultRoots(props);
if(!isOK(props) || isTerminated(props)) return;
loadLocalizationStrings(props);
if(!isOK(props) || isTerminated(props)) return;
if(isOnlyHelp(props)) return;
setProgressTitleString(props, getI18nProperty(props, MSG_PROGRESS_TITLE));
setMainWindowTitle(props, getI18nProperty(props, MAIN_WINDOW_TITLE));
showLauncherWindows(props);
if(!isOK(props) || isTerminated(props)) return;
readLauncherProperties(props);
checkExtractionStatus(props);
if(!isOK(props) || isTerminated(props)) return;
if(props->bundledNumber > 0) {
createTMPDir(props);
if(isOK(props)) {
checkFreeSpace(props, props->tmpDir, props->bundledSize);
checkExtractionStatus(props);
}
}
if (isOK(props) ){
extractJVMData(props);
checkExtractionStatus(props);
if (isOK(props) && !props->extractOnly && !isTerminated(props)) {
findSuitableJava(props);
}
if (isOK(props) && !isTerminated(props)) {
extractData(props);
checkExtractionStatus(props);
if (isOK(props) && (props->java!=NULL) && !isTerminated(props)) {
setClasspathElements(props);
if(isOK(props) && (props->java!=NULL) && !isTerminated(props)) {
setAdditionalArguments(props);
setLauncherCommand(props);
Sleep(500);
executeMainClass(props);
}
}
}
}
if(!props->extractOnly && props->tmpDirCreated) {
writeMessageA(props, OUTPUT_LEVEL_DEBUG, 0, "... deleting temporary directory ", 1);
deleteDirectory(props, props->tmpDir);
}
}