Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions HMCLCore/src/main/java/org/jackhuang/hmcl/util/StringUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,55 @@ public static boolean isNotBlank(String str) {
return !isBlank(str);
}

public static String normalizeWhitespaces(String str) {
if (str == null)
return "";

int start = 0;
int end = str.length();

while (start < str.length() && Character.isWhitespace(str.charAt(start))) {
start++;
}
while (end > start && Character.isWhitespace(str.charAt(end - 1))) {
end--;
}

if (end == start) {
return "";
}

StringBuilder builder = null;

int i = start;
while (i < end) {
char ch = str.charAt(i);
if (Character.isWhitespace(ch)) {
int whitespaceEnd = i + 1;
while (whitespaceEnd < end && Character.isWhitespace(str.charAt(whitespaceEnd))) {
whitespaceEnd++;
}

if (whitespaceEnd - i > 1 || ch != ' ') {
if (builder == null) {
builder = new StringBuilder(end - start);
builder.append(str, start, i);
}
builder.append(' ');
i = whitespaceEnd ;
continue;
}
}

if (builder != null) {
builder.append(ch);
}
i++;
}

return builder != null ? builder.toString() : str.substring(start, end);
}

public static String capitalizeFirst(String str) {
if (str == null || str.isEmpty())
return str;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,46 @@
*/
package org.jackhuang.hmcl.util.platform.hardware;

import org.jackhuang.hmcl.util.StringUtils;
import org.jetbrains.annotations.Nullable;

/**
* @author Glavo
*/
public final class CentralProcessor {

Copy link

Copilot AI May 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The cleanName method lacks a JavaDoc explaining its normalization rules and null behavior. Consider adding a description of input/output expectations and examples.

Suggested change
/**
* Normalizes a processor name by removing unnecessary details and standardizing the format.
* <p>
* This method handles specific patterns for Intel, AMD, and Loongson processors, removing
* redundant information such as core counts, trademarks, and other suffixes. If the input
* is {@code null}, the method returns {@code null}.
* </p>
*
* <p><b>Examples:</b></p>
* <ul>
* <li>Input: {@code "Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz"} → Output: {@code "Intel Core i7-9700K"}</li>
* <li>Input: {@code "AMD Ryzen 5 3600 6-Core Processor"} → Output: {@code "AMD Ryzen 5 3600"}</li>
* <li>Input: {@code "Loongson-3A R4 (Loongson-3A3000)"} → Output: {@code "Loongson-3A3000"}</li>
* <li>Input: {@code null} → Output: {@code null}</li>
* </ul>
*
* @param name the original processor name, or {@code null}
* @return the normalized processor name, or {@code null} if the input is {@code null}
*/

Copilot uses AI. Check for mistakes.
public static String cleanName(String name) {
if (name == null)
return null;
Comment thread
Glavo marked this conversation as resolved.
Copy link

Copilot AI May 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cleanName returns null when input is null but its signature doesn’t reflect that. Consider annotating the method with @Nullable or returning an empty string for consistency with normalizeWhitespaces.

Suggested change
return null;
return "";

Copilot uses AI. Check for mistakes.

int idx = name.indexOf('@');
if (idx > 0)
name = name.substring(0, idx);

name = name.replaceFirst(" (\\d+|Dual|Quad|Six|Eight|Ten)-[Cc]ores?", "");
Comment thread
Glavo marked this conversation as resolved.
name = name.replaceAll(" (CPU|FPU|APU|Processor)", "");

if (name.contains("Intel")) {
name = name.replaceFirst("^(\\d+th Gen )?Intel(\\(R\\)|®)? ", "Intel ");
name = name.replaceAll(" ([a-zA-Z]+)\\((?:TM|R|™|®)\\) ", " $1 ");
Comment thread
Glavo marked this conversation as resolved.
name = name.replace("Core(TM)2", "Core 2");
} else if (name.contains("AMD")) {
name = name.replace("(tm)", "");

idx = name.indexOf(" w/ Radeon "); // Radeon 780M Graphics
if (idx < 0)
idx = name.indexOf(" with Radeon ");
if (idx < 0)
idx = name.indexOf(" with AMD Radeon ");
if (idx > 0)
name = name.substring(0, idx);
} else if (name.contains("Loongson")) {
name = name.replaceFirst("^Loongson-3A R\\d \\((Loongson-[^)]+)\\)", "$1");
}

return StringUtils.normalizeWhitespaces(name);
}

private final String name;
private final @Nullable HardwareVendor vendor;
private final @Nullable Cores cores;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,11 +100,13 @@ private static void detectName(CentralProcessor.Builder builder, TreeMap<Integer
String modelName = firstCore.get("model name");
if (modelName == null)
modelName = firstCore.get("Model Name");
if (modelName == null)
modelName = firstCore.get("Model name");
if (modelName == null)
modelName = firstCore.get("cpu model");
Comment thread
Glavo marked this conversation as resolved.

if (modelName != null) {
builder.setName(modelName);
builder.setName(CentralProcessor.cleanName(modelName));
builder.setVendor(HardwareVendor.of(firstCore.get("vendor_id")));

if (builder.getVendor() == null && modelName.startsWith("Loongson"))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ private static void detectName(CentralProcessor.Builder builder, WinReg reg) {
Object vendor = reg.queryValue(WinReg.HKEY.HKEY_LOCAL_MACHINE, "HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0", "VendorIdentifier");

if (name instanceof String)
builder.setName((String) name);
builder.setName(CentralProcessor.cleanName((String) name));

if (vendor instanceof String)
builder.setVendor(HardwareVendor.of((String) vendor));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.util;

import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;

/**
* @author Glavo
*/
public final class StringUtilsTest {

@Test
public void testNormalizeWhitespaces() {
assertEquals("", StringUtils.normalizeWhitespaces(""));
assertEquals("", StringUtils.normalizeWhitespaces(" "));
assertEquals("", StringUtils.normalizeWhitespaces(" \t"));
assertEquals("", StringUtils.normalizeWhitespaces(" \t "));

assertEquals("abc", StringUtils.normalizeWhitespaces("abc"));
assertEquals("abc", StringUtils.normalizeWhitespaces(" abc"));
assertEquals("abc", StringUtils.normalizeWhitespaces("abc "));
assertEquals("abc", StringUtils.normalizeWhitespaces(" abc "));
assertEquals("abc", StringUtils.normalizeWhitespaces(" \tabc \t"));

assertEquals("a bc", StringUtils.normalizeWhitespaces("a bc"));
assertEquals("a bc", StringUtils.normalizeWhitespaces("a bc"));
assertEquals("a bc", StringUtils.normalizeWhitespaces("a \tbc"));
assertEquals("a bc", StringUtils.normalizeWhitespaces(" a \tbc "));
assertEquals("a b c", StringUtils.normalizeWhitespaces(" a\tb c "));
assertEquals("a b c", StringUtils.normalizeWhitespaces(" a \t b c "));
assertEquals("a b c", StringUtils.normalizeWhitespaces(" a \t b c "));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Hello Minecraft! Launcher
* Copyright (C) 2025 huangyuhui <huanghongxun2008@126.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jackhuang.hmcl.util.platform.hardware;

import org.junit.jupiter.api.Test;

import static org.jackhuang.hmcl.util.platform.hardware.CentralProcessor.cleanName;
import static org.junit.jupiter.api.Assertions.assertEquals;

/**
* @author Glavo
*/
public final class CentralProcessorTest {

@Test
public void testCleanName() {
assertEquals("Intel Core i7-12700K", cleanName("12th Gen Intel(R) Core(TM) i7-12700K"));
assertEquals("Intel Core Ultra 9 285K", cleanName("Intel(R) Core(TM) Ultra 9 285K"));
assertEquals("Intel Xeon Platinum 8380", cleanName("Intel(R) Xeon(R) Platinum 8380 CPU @ 2.30GHz"));
assertEquals("Intel Xeon E5-2660 v2", cleanName("Intel(R) Xeon(R) CPU E5-2660 v2 @ 2.20GHz"));
assertEquals("Intel Xeon Phi 7250", cleanName("Intel(R) Xeon Phi(TM) CPU 7250 @ 1.40GHz"));
assertEquals("Intel Celeron N5105", cleanName("Intel(R) Celeron(R) N5105 @ 2.00GHz"));
assertEquals("Intel Pentium Silver J5005", cleanName("Intel(R) Pentium(R) Silver J5005 CPU @ 1.50GHz"));
assertEquals("Intel Atom E3940", cleanName("Intel(R) Atom(TM) Processor E3940 @ 1.60GHz"));
assertEquals("Intel Core i7 X 990", cleanName("Intel(R) Core(TM) i7 CPU X 990 @ 3.47GHz"));
assertEquals("Intel Core 2 Duo T7500", cleanName("Intel(R) Core(TM)2 Duo CPU T7500 @ 2.20GHz"));
assertEquals("Intel Core 2 Quad Q9500", cleanName("Intel(R) Core(TM)2 Quad CPU Q9500 @ 2.83GHz"));

assertEquals("AMD Ryzen 7 7840HS", cleanName("AMD Ryzen 7 7840HS w/ Radeon 780M Graphics"));
assertEquals("AMD Ryzen 7 6800U", cleanName("AMD Ryzen 7 6800U with Radeon Graphics"));
assertEquals("AMD Ryzen 7 5800X", cleanName("AMD Ryzen 7 5800X 8-Core Processor"));
assertEquals("AMD Ryzen 5 2400G", cleanName("AMD Ryzen 5 2400G with Radeon Vega Graphics"));
assertEquals("AMD EPYC 7713", cleanName("AMD EPYC 7713 64-Core Processor"));
assertEquals("AMD Ryzen Threadripper 3960X", cleanName("AMD Ryzen Threadripper 3960X 24-Core Processor"));
assertEquals("AMD Ryzen Threadripper PRO 5995WX", cleanName("AMD Ryzen Threadripper PRO 5995WX 64-Cores"));
assertEquals("AMD Ryzen Embedded V2748", cleanName("AMD Ryzen Embedded V2748 with Radeon Graphics"));
assertEquals("AMD A8-7410", cleanName("AMD A8-7410 APU with AMD Radeon R5 Graphics"));
assertEquals("AMD FX-8350", cleanName("AMD FX(tm)-8350 Eight-Core Processor"));
assertEquals("AMD Phenom II X6 1055T", cleanName("AMD Phenom(tm) II X6 1055T Processor"));
assertEquals("AMD Athlon 5350", cleanName("AMD Athlon(tm) 5350 APU with Radeon(tm) R3"));

assertEquals("Hygon C86 7285", cleanName("Hygon C86 7285 32-core Processor"));
assertEquals("Hygon C86 3250", cleanName("Hygon C86 3250 8-core Processor"));

assertEquals("ZHAOXIN KaiXian KX-6640MA", cleanName("ZHAOXIN KaiXian KX-6640MA@2.2+GHz"));
assertEquals("ZHAOXIN KaiXian KX-U6780A", cleanName("ZHAOXIN KaiXian KX-U6780A@2.7GHz"));
assertEquals("ZHAOXIN KaiSheng KH-40000/16", cleanName("ZHAOXIN KaiSheng KH-40000/16@2.2GHz"));
assertEquals("ZHAOXIN KaiSheng KH-37800D", cleanName("ZHAOXIN KaiSheng KH-37800D@2.7GHz"));

assertEquals("Loongson-3A3000", cleanName("Loongson-3A R3 (Loongson-3A3000) @ 1400MHz"));
assertEquals("Loongson-3B4000", cleanName("Loongson-3A R4 (Loongson-3B4000) @ 1800MHz"));
}
}