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;
|
2023-06-18 15:03:02 -07:00
|
|
|
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;
|
2024-04-20 10:36:12 -07:00
|
|
|
import java.util.*;
|
2023-06-18 15:03:02 -07:00
|
|
|
import java.util.regex.Pattern;
|
2020-05-16 21:58:38 -07:00
|
|
|
|
|
|
|
public class EnumIniField extends IniField {
|
|
|
|
private final FieldType type;
|
2023-06-18 15:03:02 -07:00
|
|
|
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
|
|
|
|
2023-06-18 15:03:02 -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
|
|
|
}
|
|
|
|
|
2023-06-18 15:03:02 -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())
|
2023-11-25 15:27:24 -08:00
|
|
|
throw new IllegalStateException("Ordinal out of range " + ordinal + " in " + getName());
|
2020-07-31 09:36:53 -07:00
|
|
|
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);
|
2020-06-17 17:33:17 -07:00
|
|
|
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
|
|
|
}
|
2020-06-17 17:33:17 -07:00
|
|
|
|
2023-06-18 15:03:02 -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;
|
|
|
|
}
|
|
|
|
|
2020-06-17 17:33:17 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2023-06-18 15:03:02 -07:00
|
|
|
|
|
|
|
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);
|
2023-06-18 15:03:02 -07:00
|
|
|
|
|
|
|
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) {
|
2023-06-18 15:03:02 -07:00
|
|
|
Map<Integer, String> keyValues = new TreeMap<>();
|
|
|
|
|
2024-02-14 12:55:32 -08:00
|
|
|
boolean isKeyValueSyntax = isKeyValueSyntax(rawText);
|
2023-06-18 15:03:02 -07:00
|
|
|
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];
|
2024-04-20 10:36:12 -07:00
|
|
|
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]);
|
|
|
|
}
|
2023-06-18 15:03:02 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2023-06-18 15:03:02 -07:00
|
|
|
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
|
|
|
}
|