rusefi/java_console/inifile/src/main/java/com/opensr5/ini/field/EnumIniField.java

230 lines
7.8 KiB
Java
Raw Normal View History

2020-05-16 21:58:38 -07:00
package com.opensr5.ini.field;
import com.opensr5.ConfigurationImage;
2023-11-25 15:49:17 -08:00
import com.opensr5.ini.IniFileModel;
import com.opensr5.ini.IniFileReader;
import com.opensr5.ini.RawIniFile;
2020-05-16 21:58:38 -07:00
import com.rusefi.config.FieldType;
2020-06-12 23:29:42 -07:00
import com.rusefi.tune.xml.Constant;
2020-06-13 17:27:39 -07:00
import org.jetbrains.annotations.NotNull;
2020-05-16 21:58:38 -07:00
2020-06-12 23:29:42 -07:00
import javax.management.ObjectName;
2020-06-13 17:27:39 -07:00
import java.nio.ByteBuffer;
import java.util.*;
import java.util.regex.Pattern;
2020-05-16 21:58:38 -07:00
public class EnumIniField extends IniField {
private final FieldType type;
private final EnumKeyValueMap enums;
2020-05-16 21:58:38 -07:00
private final int bitPosition;
2020-06-13 19:29:23 -07:00
// weird format where 'one bit' width means 0 and "two bits" means "1"
private final int bitSize0;
2020-05-16 21:58:38 -07:00
public EnumIniField(String name, int offset, FieldType type, EnumKeyValueMap enums, int bitPosition, int bitSize0) {
2020-05-16 21:58:38 -07:00
super(name, offset);
this.type = type;
this.enums = enums;
this.bitPosition = bitPosition;
2020-06-13 19:29:23 -07:00
this.bitSize0 = bitSize0;
2020-05-16 21:58:38 -07:00
}
2020-06-13 18:51:09 -07:00
@Override
public int getSize() {
return type.getStorageSize();
}
2020-05-16 21:58:38 -07:00
public int getBitPosition() {
return bitPosition;
}
2020-06-13 19:29:23 -07:00
public int getBitSize0() {
return bitSize0;
2020-05-16 21:58:38 -07:00
}
public EnumKeyValueMap getEnums() {
2020-05-16 21:58:38 -07:00
return enums;
}
public FieldType getType() {
return type;
}
@Override
public String getValue(ConfigurationImage image) {
2020-06-13 17:27:39 -07:00
int ordinal = getByteBuffer(image).getInt();
2020-06-13 19:29:23 -07:00
ordinal = getBitRange(ordinal, bitPosition, bitSize0 + 1);
2020-05-16 21:58:38 -07:00
if (ordinal >= enums.size())
throw new IllegalStateException("Ordinal out of range " + ordinal + " in " + getName());
return "\"" + enums.get(ordinal) + "\"";
2020-05-16 21:58:38 -07:00
}
2020-06-13 17:27:39 -07:00
@NotNull
private ByteBuffer getByteBuffer(ConfigurationImage image) {
return image.getByteBuffer(getOffset(), 4);
}
2022-10-07 08:57:04 -07:00
public static boolean isQuoted(String q) {
2020-06-12 23:29:42 -07:00
final int len = q.length();
return (len >= 2 && q.charAt(0) == '"' && q.charAt(len - 1) == '"');
}
@Override
public void setValue(ConfigurationImage image, Constant constant) {
String v = constant.getValue();
int ordinal = enums.indexOf(isQuoted(v) ? ObjectName.unquote(v) : v);
if (ordinal == -1)
throw new IllegalArgumentException("Not found " + v);
2020-06-13 17:27:39 -07:00
int value = getByteBuffer(image).getInt();
2020-06-13 19:29:23 -07:00
value = setBitRange(value, ordinal, bitPosition, bitSize0 + 1);
2020-06-13 17:27:39 -07:00
getByteBuffer(image).putInt(value);
}
2020-06-13 18:51:09 -07:00
@Override
public String toString() {
return "EnumIniField{" +
"name=" + getName() +
", offset=" + getOffset() +
", type=" + type +
", enums=" + enums +
", bitPosition=" + bitPosition +
2020-06-13 19:29:23 -07:00
", bitSize=" + bitSize0 +
2020-06-13 18:51:09 -07:00
'}';
}
2020-06-13 17:27:39 -07:00
public static int setBitRange(int value, int ordinal, int bitPosition, int bitSize) {
2020-06-13 19:29:23 -07:00
if (ordinal >= (1 << bitSize))
throw new IllegalArgumentException("Ordinal overflow " + ordinal + " does not fit in " + bitSize + " bit(s)");
2020-06-13 17:27:39 -07:00
int num = ((1 << bitSize) - 1) << bitPosition;
int clearBitRange = value & ~num;
2020-06-13 19:29:23 -07:00
return (clearBitRange + (ordinal << bitPosition));
2020-06-12 23:29:42 -07:00
}
2020-05-30 08:31:18 -07:00
public static boolean getBit(int ordinal, int bitPosition) {
2020-06-13 19:29:23 -07:00
return getBitRange(ordinal, bitPosition, 1) == 1;
2020-05-30 08:31:18 -07:00
}
2020-05-16 21:58:38 -07:00
public static int getBitRange(int ordinal, int bitPosition, int bitSize) {
ordinal = ordinal >> bitPosition;
2020-06-13 19:29:23 -07:00
ordinal = ordinal & ((1 << (bitSize)) - 1);
2020-05-16 21:58:38 -07:00
return ordinal;
}
2023-11-25 15:49:17 -08:00
public static EnumIniField parse(LinkedList<String> list, RawIniFile.Line line, IniFileModel iniFileModel) {
2020-05-16 21:58:38 -07:00
String name = list.get(0);
FieldType type = FieldType.parseTs(list.get(2));
int offset = Integer.parseInt(list.get(3));
String bitRange = list.get(4);
ParseBitRange parseBitRange = new ParseBitRange().invoke(bitRange);
int bitPosition = parseBitRange.getBitPosition();
int bitSize0 = parseBitRange.getBitSize0();
2020-05-16 21:58:38 -07:00
2023-11-25 15:49:17 -08:00
EnumKeyValueMap enums = EnumKeyValueMap.valueOf(line.getRawText(), iniFileModel);
2020-06-13 19:29:23 -07:00
return new EnumIniField(name, offset, type, enums, bitPosition, bitSize0);
2020-05-16 21:58:38 -07:00
}
public static int ordinalIndexOf(String str, String substr, int n) {
int pos = str.indexOf(substr);
while (--n > 0 && pos != -1)
pos = str.indexOf(substr, pos + 1);
return pos;
}
public static class ParseBitRange {
private int bitPosition;
private int bitSize0;
public int getBitPosition() {
return bitPosition;
}
public int getBitSize0() {
return bitSize0;
}
public ParseBitRange invoke(String bitRange) {
bitRange = bitRange.replaceAll("[\\]\\[:]", " ").trim();
String bitPositions[] = bitRange.split(" ");
if (bitPositions.length != 2)
throw new IllegalStateException("Bit position " + bitRange);
bitPosition = Integer.parseInt(bitPositions[0]);
bitSize0 = Integer.parseInt(bitPositions[1]) - bitPosition;
return this;
}
}
public static class EnumKeyValueMap {
private static final String STARTS_WITH_NUMBERS_OPTIONAL_SPACES_AND_EQUALS = "^\\d+\\s*=.*";
2024-02-14 13:02:01 -08:00
private static final Pattern IS_KEY_VALUE_SYNTAX = Pattern.compile(STARTS_WITH_NUMBERS_OPTIONAL_SPACES_AND_EQUALS);
private final Map<Integer, String> keyValues;
public EnumKeyValueMap(Map<Integer, String> keyValues) {
this.keyValues = keyValues;
}
2023-11-25 15:49:17 -08:00
public static EnumKeyValueMap valueOf(String rawText, IniFileModel iniFileModel) {
Map<Integer, String> keyValues = new TreeMap<>();
2024-02-14 12:55:32 -08:00
boolean isKeyValueSyntax = isKeyValueSyntax(rawText);
int offset = 5;
String[] tokens = IniFileReader.splitTokens(rawText);
if (isKeyValueSyntax) {
for (int i = 0; i < tokens.length - offset; i += 2) {
keyValues.put(Integer.valueOf(tokens[i + offset]), tokens[i + offset + 1]);
}
} else {
2023-11-25 15:49:17 -08:00
String firstValue = tokens[offset];
String trimmed = firstValue.trim();
if (trimmed.startsWith("$")) {
String key = trimmed.substring(1);
List<String> elements = iniFileModel.defines.get(key);
Objects.requireNonNull(elements, "Elements for " + key);
2023-11-25 15:49:17 -08:00
for (int i = 0; i < elements.size(); i++) {
keyValues.put(i, elements.get(i));
}
} else {
for (int i = 0; i < tokens.length - offset; i++) {
keyValues.put(i, tokens[i + offset]);
}
}
}
return new EnumKeyValueMap(keyValues);
}
2024-02-14 13:02:01 -08:00
public static boolean isKeyValueSyntax(String rawText) {
2024-02-14 12:55:32 -08:00
String interestingPart = getEnumValuesSection(rawText);
return IS_KEY_VALUE_SYNTAX.matcher(interestingPart).matches();
}
public int size() {
return keyValues.size();
}
public String get(int ordinal) {
return keyValues.get(ordinal);
}
public int indexOf(String value) {
for (Map.Entry<Integer, String> e : keyValues.entrySet()) {
if (e.getValue().equals(value))
return e.getKey();
}
throw new IllegalArgumentException("Nothing for " + value);
}
}
2024-02-14 12:55:32 -08:00
@NotNull
2024-02-14 13:02:01 -08:00
public static String getEnumValuesSection(String rawText) {
2024-02-14 12:55:32 -08:00
int interestingIndex = EnumIniField.ordinalIndexOf(rawText, ",", 4);
// yes that could have been done with a regex as well
return rawText.substring(interestingIndex + /*skipping comma*/1).trim();
}
2020-05-16 21:58:38 -07:00
}