diff --git a/head/consolehead.o b/head/consolehead.o index 60bb62f..7d9b65a 100644 Binary files a/head/consolehead.o and b/head/consolehead.o differ diff --git a/head/guihead.o b/head/guihead.o index 7cff132..2924163 100644 Binary files a/head/guihead.o and b/head/guihead.o differ diff --git a/head/head.o b/head/head.o index a5b1e2b..5754c39 100644 Binary files a/head/head.o and b/head/head.o differ diff --git a/head_src/head.c b/head_src/head.c index 7457336..9615a93 100644 --- a/head_src/head.c +++ b/head_src/head.c @@ -312,27 +312,95 @@ BOOL regQueryValue(const char* regPath, unsigned char* buffer, return result; } -void formatJavaVersion(char* version, const char* originalVersion) -{ - char* updatePart = strchr(originalVersion, '_'); +int findNextVersionPart(const char* startAt) { + if (startAt == NULL || strlen(startAt) == 0) { + return 0; + } - if (updatePart != NULL) - { - // skip underscore - updatePart++; + char* firstSeparatorA = strchr(startAt, '.'); + char* firstSeparatorB = strchr(startAt, '_'); + char* firstSeparator; + if (firstSeparatorA == NULL) { + firstSeparator = firstSeparatorB; + } else if (firstSeparatorB == NULL) { + firstSeparator = firstSeparatorA; + } else { + firstSeparator = min(firstSeparatorA, firstSeparatorB); + } - if (strlen(updatePart) < 3) - { - const int majorVersionLength = updatePart - originalVersion; - strncpy(version, originalVersion, majorVersionLength); - *(version + majorVersionLength) = 0; - strcat(version, "0"); - strcat(version, updatePart); - return; - } - } - - strcpy(version, originalVersion); + if (firstSeparator == NULL) { + return strlen(startAt); + } + + return firstSeparator - startAt; +} + +/** + * This method will take java version from `originalVersion` string and convert/format it + * into `version` string that can be used for string comparison with other versions. + * + * Due to different version schemas <=8 vs. >=9 it will "normalize" versions to 1 format + * so we can directly compare old and new versions. + */ +#define JRE_VER_MAX_DIGITS_PER_PART 3 +void formatJavaVersion(char* version, const char* originalVersion) { + strcpy(version, ""); + if (originalVersion == NULL || strlen(originalVersion) == 0) { + return; + } + + int partsAdded = 0; + int i; + char* pos = (char*) originalVersion; + int curPartLen; + while ((curPartLen = findNextVersionPart(pos)) > 0) { + char number[curPartLen + 1]; + memset(number, 0, curPartLen + 1); + strncpy(number, pos, curPartLen); + + if (partsAdded == 0 && (curPartLen != 1 || number[0] != '1')) { + // NOTE: When it's java 9+ we'll add "1" as the first part of the version + strcpy(version, "1"); + partsAdded++; + } + + if (partsAdded < 3) { + if (partsAdded > 0) { + strcat(version, "."); + } + for (i = 0; + (partsAdded > 0) + && (i < JRE_VER_MAX_DIGITS_PER_PART - strlen(number)); + i++) { + strcat(version, "0"); + } + strcat(version, number); + } else if (partsAdded == 3) { + // add as an update + strcat(version, "_"); + for (i = 0; i < JRE_VER_MAX_DIGITS_PER_PART - strlen(number); i++) { + strcat(version, "0"); + } + strcat(version, number); + } else if (partsAdded == 4) { + // TODO: Add warning + break; + } + partsAdded++; + + pos += curPartLen + 1; + if (pos >= originalVersion + strlen(originalVersion)) { + break; + } + } + + for (i = partsAdded; i < 3; i++) { + strcat(version, "."); + int j; + for (j = 0; j < JRE_VER_MAX_DIGITS_PER_PART; j++) { + strcat(version, "0"); + } + } } void regSearch(const char* keyName, const int searchType) diff --git a/src/net/sf/launch4j/config/Jre.java b/src/net/sf/launch4j/config/Jre.java index bd88602..f4e8df9 100644 --- a/src/net/sf/launch4j/config/Jre.java +++ b/src/net/sf/launch4j/config/Jre.java @@ -54,8 +54,8 @@ public class Jre implements IValidatable { public static final String ARGS = "jvmArgs"; // __________________________________________________________________________________ - public static final String VERSION_PATTERN = "(\\d\\.){2}\\d(_\\d+)?"; - + public static final String VERSION_PATTERN = "((\\d\\.){2}\\d(_\\d+)?)|(\\d+(\\.\\d+)*)"; + public static final String JDK_PREFERENCE_JRE_ONLY = "jreOnly"; public static final String JDK_PREFERENCE_PREFER_JRE = "preferJre"; public static final String JDK_PREFERENCE_PREFER_JDK = "preferJdk"; @@ -116,7 +116,7 @@ public void checkInvariants() { if (!Validator.isEmpty(maxVersion)) { Validator.checkFalse(Validator.isEmpty(minVersion), "jre.minVersion", Messages.getString("Jre.specify.min.version")); - Validator.checkTrue(minVersion.compareTo(maxVersion) < 0, + Validator.checkTrue(JreVersion.parseString(minVersion).compareTo(JreVersion.parseString(maxVersion)) < 0, "jre.maxVersion", Messages.getString("Jre.max.greater.than.min")); } Validator.checkTrue(initialHeapSize == null || maxHeapSize != null, diff --git a/src/net/sf/launch4j/config/JreVersion.java b/src/net/sf/launch4j/config/JreVersion.java new file mode 100644 index 0000000..a12982d --- /dev/null +++ b/src/net/sf/launch4j/config/JreVersion.java @@ -0,0 +1,121 @@ +package net.sf.launch4j.config; + +/** + * This class will abstract application from JRE versioning schema and provide + * comparing capabilities + * + * @author sergeyk + * + */ +public class JreVersion implements Comparable { + private int x1; + private int x2; + private int x3; + private int x4; + + public static JreVersion parseString(String versionStr) { + JreVersion ret = new JreVersion(); + if (versionStr == null || versionStr.trim().length() == 0) { + return ret; + } + if (!versionStr.matches(Jre.VERSION_PATTERN)) { + // NOTE: This is actually shouldn't happen because version format had to be + // checked by Jre#checkInvariants BEFORE calling this method + throw new IllegalArgumentException("JRE version is not in a right format."); + } + + String[] parts = versionStr.split("[\\._]"); + int first = Integer.parseInt(parts[0]); + if (first >= 9) { + // java 9+ version schema + ret.x1 = 1; + ret.x2 = first; + if (parts.length >= 2) { + ret.x3 = Integer.parseInt(parts[1]); + if (parts.length >= 3) { + ret.x4 = Integer.parseInt(parts[2]); + } + } + } else { + // java <= 1.8 version schema + ret.x1 = first; + + ret.x2 = Integer.parseInt(parts[1]); + ret.x3 = Integer.parseInt(parts[2]); + if (parts.length == 4) { + ret.x4 = Integer.parseInt(parts[3]); + } + } + + return ret; + } + + @Override + public String toString() { + if (x2 >= 9) { + return "" + x2 + "." + x3 + "." + x4; + } + + return "" + x1 + "." + x2 + "." + x3 + (x4 > 0 ? "_" + x4 : ""); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + x1; + result = prime * result + x2; + result = prime * result + x3; + result = prime * result + x4; + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + JreVersion other = (JreVersion) obj; + if (x1 != other.x1) { + return false; + } + if (x2 != other.x2) { + return false; + } + if (x3 != other.x3) { + return false; + } + if (x4 != other.x4) { + return false; + } + return true; + } + + @Override + public int compareTo(JreVersion o) { + if (this.equals(o)) { + return 0; + } + + if (x1 != o.x1) { + return x1 - o.x1; + } + if (x2 != o.x2) { + return x2 - o.x2; + } + if (x3 != o.x3) { + return x3 - o.x3; + } + if (x4 != o.x4) { + return x4 - o.x4; + } + + throw new IllegalStateException("If you see this exception it means JreVersion::equals() method is buggy"); + } +}