mirror of https://github.com/rusefi/RomRaider.git
Implemented Maskable and Switchable 2D Tables
This commit is contained in:
parent
8338746442
commit
c6ea31c986
|
@ -1,6 +1,14 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2017 RomRaider.com
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
* Copyright (C) 2006-2020 RomRaider.com
|
||||
=======
|
||||
* Copyright (C) 2006-2019 RomRaider.com
|
||||
>>>>>>> Added XOR for single byte checksums. Added possibility of multiple checksums in file
|
||||
=======
|
||||
* Copyright (C) 2006-2020 RomRaider.com
|
||||
>>>>>>> Updated copyright. Switched to checkboxes for presets. Allowed multiple selection. Fixed saving bug. CChanged table name to 2DMaskedSwitchable
|
||||
*
|
||||
* 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
|
||||
|
@ -34,6 +42,7 @@ import java.io.Serializable;
|
|||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Vector;
|
||||
|
||||
|
@ -63,7 +72,7 @@ public class Rom extends DefaultMutableTreeNode implements Serializable {
|
|||
private final Vector<TableTreeNode> tableNodes = new Vector<TableTreeNode>();
|
||||
private byte[] binData;
|
||||
private boolean isAbstract = false;
|
||||
private ChecksumManager checksumManager;
|
||||
private LinkedList<ChecksumManager> checksumManagers = new LinkedList<ChecksumManager>();
|
||||
|
||||
public Rom() {
|
||||
tableNodes.clear();
|
||||
|
@ -186,7 +195,8 @@ public class Rom extends DefaultMutableTreeNode implements Serializable {
|
|||
Table table = tableNodes.get(i).getTable();
|
||||
try {
|
||||
// if storageaddress has not been set (or is set to 0) omit table
|
||||
if (table.getStorageAddress() != 0) {
|
||||
//Why can the address not be zero? - Changed
|
||||
if (table.getStorageAddress() >= 0) {
|
||||
try {
|
||||
table.populateTable(binData, this.getRomID().getRamOffset());
|
||||
TableUpdateHandler.getInstance().registerTable(table);
|
||||
|
@ -422,34 +432,42 @@ public class Rom extends DefaultMutableTreeNode implements Serializable {
|
|||
return (DefaultMutableTreeNode) super.getLastChild();
|
||||
}
|
||||
|
||||
public void setChecksumManager(ChecksumManager checksumManager) {
|
||||
this.checksumManager = checksumManager;
|
||||
public void addChecksumManager(ChecksumManager checksumManager) {
|
||||
this.checksumManagers.add(checksumManager);
|
||||
}
|
||||
|
||||
public ChecksumManager getChecksumType() {
|
||||
return checksumManager;
|
||||
public ChecksumManager getChecksumType(int index) {
|
||||
return checksumManagers.get(index);
|
||||
}
|
||||
|
||||
public void validateChecksum() {
|
||||
if (checksumManager != null) {
|
||||
if (!checksumManagers.isEmpty()) {
|
||||
final String message = String.format(
|
||||
"Checksum is invalid.%n" +
|
||||
"At least one Checksum is invalid.%n" +
|
||||
"The ROM image may be corrupt or it has been " +
|
||||
"hex edited manually.%n" +
|
||||
"The checksum can be corrected when the ROM " +
|
||||
"is saved if your trust it is not corrupt.");
|
||||
if (!checksumManager.validate(binData)) {
|
||||
showMessageDialog(null,
|
||||
message,
|
||||
"ERROR - Checksum Failed",
|
||||
WARNING_MESSAGE);
|
||||
|
||||
boolean valid = true;
|
||||
|
||||
for(ChecksumManager cm: checksumManagers) {
|
||||
if (!cm.validate(binData)) valid = false;
|
||||
}
|
||||
|
||||
if(!valid)
|
||||
showMessageDialog(null,
|
||||
message,
|
||||
"ERROR - At least one Checksum Failed",
|
||||
WARNING_MESSAGE);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateChecksum() {
|
||||
if (checksumManager != null) {
|
||||
checksumManager.update(binData);
|
||||
if (!checksumManagers.isEmpty()) {
|
||||
for(ChecksumManager cm: checksumManagers) {
|
||||
cm.update(binData);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
* Copyright (C) 2006-2020 RomRaider.com
|
||||
*
|
||||
* 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
|
||||
|
@ -778,7 +778,7 @@ public abstract class Table extends JPanel implements Serializable {
|
|||
return JEPUtil.evaluate(getCurrentScale().getExpression(), getMinAllowedBin());
|
||||
}
|
||||
|
||||
private void calcValueRange() {
|
||||
protected void calcValueRange() {
|
||||
if (getStorageType() != Settings.STORAGE_TYPE_FLOAT) {
|
||||
if (isSignedData()) {
|
||||
switch (getStorageType()) {
|
||||
|
@ -820,34 +820,36 @@ public abstract class Table extends JPanel implements Serializable {
|
|||
}
|
||||
|
||||
public void calcCellRanges() {
|
||||
double binMax = data[0].getBinValue();
|
||||
double binMin = data[0].getBinValue();
|
||||
if(data.length > 0) {
|
||||
double binMax = data[0].getBinValue();
|
||||
double binMin = data[0].getBinValue();
|
||||
|
||||
double compareMax = data[0].getCompareValue();
|
||||
double compareMin = data[0].getCompareValue();
|
||||
double compareMax = data[0].getCompareValue();
|
||||
double compareMin = data[0].getCompareValue();
|
||||
|
||||
for(DataCell cell : data) {
|
||||
// Calc bin
|
||||
if(binMax < cell.getBinValue()) {
|
||||
binMax = cell.getBinValue();
|
||||
}
|
||||
if(binMin > cell.getBinValue()) {
|
||||
binMin = cell.getBinValue();
|
||||
}
|
||||
for(DataCell cell : data) {
|
||||
// Calc bin
|
||||
if(binMax < cell.getBinValue()) {
|
||||
binMax = cell.getBinValue();
|
||||
}
|
||||
if(binMin > cell.getBinValue()) {
|
||||
binMin = cell.getBinValue();
|
||||
}
|
||||
|
||||
// Calc compare
|
||||
double compareValue = cell.getCompareValue();
|
||||
if(compareMax < compareValue) {
|
||||
compareMax = compareValue;
|
||||
}
|
||||
if(compareMin > compareValue) {
|
||||
compareMin = compareValue;
|
||||
}
|
||||
}
|
||||
setMaxBin(binMax);
|
||||
setMinBin(binMin);
|
||||
setMaxCompare(compareMax);
|
||||
setMinCompare(compareMin);
|
||||
// Calc compare
|
||||
double compareValue = cell.getCompareValue();
|
||||
if(compareMax < compareValue) {
|
||||
compareMax = compareValue;
|
||||
}
|
||||
if(compareMin > compareValue) {
|
||||
compareMin = compareValue;
|
||||
}
|
||||
}
|
||||
setMaxBin(binMax);
|
||||
setMinBin(binMin);
|
||||
setMaxCompare(compareMax);
|
||||
setMinCompare(compareMin);
|
||||
}
|
||||
}
|
||||
|
||||
public double getMaxBin() {
|
||||
|
@ -1521,7 +1523,8 @@ public abstract class Table extends JPanel implements Serializable {
|
|||
TABLE_3D(3),
|
||||
X_AXIS(4),
|
||||
Y_AXIS(5),
|
||||
SWITCH(6);
|
||||
SWITCH(6),
|
||||
TABLE_2D_MASKED_SWITCHABLE(7);
|
||||
|
||||
private final int marshallingCode;
|
||||
|
||||
|
@ -1534,6 +1537,7 @@ public abstract class Table extends JPanel implements Serializable {
|
|||
case TABLE_1D:
|
||||
return 1;
|
||||
case TABLE_2D:
|
||||
case TABLE_2D_MASKED_SWITCHABLE:
|
||||
return 2;
|
||||
case TABLE_3D:
|
||||
return 3;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
* Copyright (C) 2006-2020 RomRaider.com
|
||||
*
|
||||
* 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
|
||||
|
@ -63,6 +63,14 @@ public class Table2D extends Table {
|
|||
return axis;
|
||||
}
|
||||
|
||||
public JLabel getAxisLabel() {
|
||||
return axisLabel;
|
||||
}
|
||||
|
||||
public void setAxisLabel(JLabel label) {
|
||||
axisLabel = label;
|
||||
}
|
||||
|
||||
public void setAxis(Table1D axis) {
|
||||
this.axis = axis;
|
||||
axis.setAxisParent(this);
|
||||
|
|
|
@ -0,0 +1,355 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2020 RomRaider.com
|
||||
*
|
||||
* 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 2 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, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.romraider.maps;
|
||||
|
||||
import java.awt.BorderLayout;
|
||||
import java.awt.Color;
|
||||
import java.awt.Font;
|
||||
import java.awt.GridLayout;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.JCheckBox;
|
||||
import javax.swing.JLabel;
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import com.romraider.Settings;
|
||||
import com.romraider.Settings.Endian;
|
||||
import com.romraider.util.ByteUtil;
|
||||
import com.romraider.xml.RomAttributeParser;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class Table2DMaskedSwitchable extends Table2D {
|
||||
private int bitMask;
|
||||
private LinkedList<PresetEntry> defaultEntries = new LinkedList<PresetEntry>();
|
||||
private final List<PresetButton> buttonGroup = new ArrayList<PresetButton>();
|
||||
|
||||
//Struct for saving Preset values
|
||||
private class PresetEntry {
|
||||
String name;
|
||||
LinkedList<Integer> data;
|
||||
}
|
||||
|
||||
public Table2DMaskedSwitchable() {
|
||||
super();
|
||||
}
|
||||
|
||||
public void setBitMask(int mask) {
|
||||
//Clamp mask to max size
|
||||
bitMask = (int) Math.min(mask, Math.pow(2,getStorageType()*8)-1);
|
||||
calcValueRange();
|
||||
}
|
||||
|
||||
public int getBitMask() {
|
||||
return bitMask;
|
||||
}
|
||||
|
||||
public void setStringMask(String stringMask) {
|
||||
int mask = parseUnsignedInt(stringMask, 16);
|
||||
setBitMask(mask);
|
||||
}
|
||||
|
||||
public void setPredefinedOption(String name, String data) {
|
||||
PresetEntry entry = new PresetEntry();
|
||||
entry.data = new LinkedList<Integer>();
|
||||
|
||||
|
||||
for (String s : data.split(",")) {
|
||||
Integer i = parseUnsignedInt(s, 16);
|
||||
|
||||
if (getStorageType() > 1 && getEndian() == Endian.LITTLE)
|
||||
{
|
||||
if(getStorageType() == 2) {
|
||||
i = Short.reverseBytes((short)(i&0xFFFF))&0xFFFF;
|
||||
}
|
||||
|
||||
else if(getStorageType() == 4)
|
||||
i = Integer.reverseBytes(i);
|
||||
|
||||
}
|
||||
|
||||
entry.data.add(i);
|
||||
}
|
||||
|
||||
entry.name = name;
|
||||
|
||||
defaultEntries.add(entry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateTable(byte[] input, int romRamOffset) throws ArrayIndexOutOfBoundsException, IndexOutOfBoundsException {
|
||||
super.populateTable(input, romRamOffset);
|
||||
|
||||
// temporarily remove lock
|
||||
boolean tempLock = locked;
|
||||
locked = false;
|
||||
|
||||
// Saves the masked value in dataCell
|
||||
for (int i = 0; i < getDataSize(); i++) {
|
||||
// populate data cells
|
||||
if (storageType == Settings.STORAGE_TYPE_FLOAT) { // float storage type
|
||||
LOGGER.error("Float is not supported for Table2DMaskedSwitchable!");
|
||||
return;
|
||||
|
||||
} else if (storageType == Settings.STORAGE_TYPE_MOVI20 || storageType == Settings.STORAGE_TYPE_MOVI20S) {
|
||||
LOGGER.error("MOVI20(S) is not supported for Table2DMaskedSwitchable!");
|
||||
return;
|
||||
|
||||
} else {
|
||||
double binValue = RomAttributeParser.parseByteValueMasked(input, endian, getStorageAddress() + i * storageType - ramOffset, storageType, signed, bitMask);
|
||||
|
||||
data[i].setBinValue(binValue);
|
||||
}
|
||||
|
||||
// show locked cell
|
||||
if (tempLock) {
|
||||
data[i].setForeground(Color.GRAY);
|
||||
}
|
||||
}
|
||||
|
||||
JLabel axisLabel = getAxisLabel();
|
||||
|
||||
if(getAxis().isStaticDataTable()) {
|
||||
axisLabel.setText(" " + axisLabel.getText() + " ");
|
||||
Font f = axisLabel.getFont();
|
||||
axisLabel.setFont(f.deriveFont(f.getStyle() | Font.BOLD));
|
||||
}
|
||||
|
||||
JPanel radioPanel = new JPanel(new GridLayout(0, 1));
|
||||
|
||||
// Add presets
|
||||
if(defaultEntries.size() > 0) {
|
||||
JLabel optionLabel = new JLabel(" Presets");
|
||||
|
||||
Font f = optionLabel.getFont();
|
||||
optionLabel.setFont(f.deriveFont(f.getStyle() | Font.BOLD));
|
||||
radioPanel.add(optionLabel);
|
||||
}
|
||||
|
||||
//Setup button for each preset
|
||||
for (PresetEntry entry : defaultEntries) {
|
||||
PresetButton button = new PresetButton();
|
||||
|
||||
button.setText(entry.name);
|
||||
button.setPresetData(entry.data);
|
||||
|
||||
button.addActionListener(new PresetListener());
|
||||
|
||||
buttonGroup.add(button);
|
||||
radioPanel.add(button);
|
||||
}
|
||||
|
||||
add(radioPanel, BorderLayout.SOUTH);
|
||||
|
||||
// reset locked status
|
||||
locked = tempLock;
|
||||
|
||||
calcValueRange();
|
||||
calcCellRanges();
|
||||
|
||||
repaint();
|
||||
}
|
||||
|
||||
//New values, check if any presets are active
|
||||
@Override
|
||||
public void repaint() {
|
||||
super.repaint();
|
||||
|
||||
if (buttonGroup != null) {
|
||||
for (PresetButton button: buttonGroup) {
|
||||
button.checkIfActive();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void calcValueRange() {
|
||||
if (getStorageType() != Settings.STORAGE_TYPE_FLOAT) {
|
||||
if (!isSignedData()) {
|
||||
maxAllowedBin =(int)(Math.pow(2,ByteUtil.lengthOfMask(bitMask)) - 1);
|
||||
minAllowedBin = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] saveFile(byte[] binData) {
|
||||
if (userLevel <= getSettings().getUserLevel() && (userLevel < 5 || getSettings().isSaveDebugTables())) {
|
||||
|
||||
binData = getAxis().saveFile(binData);
|
||||
|
||||
for (int i = 0; i < data.length; i++) {
|
||||
byte[] output = null;
|
||||
|
||||
if (this.isStaticDataTable() && storageType > 0) {
|
||||
LOGGER.warn("Static data table: " + this.getName() + ", storageType: " + storageType);
|
||||
}
|
||||
if (storageType != Settings.STORAGE_TYPE_FLOAT) {
|
||||
|
||||
if (!this.isStaticDataTable() && storageType > 0) {
|
||||
// Shift left again
|
||||
int tempData = (int) data[i].getBinValue() << ByteUtil.firstOneOfMask(bitMask);
|
||||
|
||||
output = RomAttributeParser.parseIntegerValue(tempData, endian, storageType);
|
||||
}
|
||||
|
||||
int byteLength = storageType;
|
||||
int tempBitMask = 0;
|
||||
|
||||
for (int z = 0; z < byteLength; z++) { // insert into file
|
||||
|
||||
tempBitMask = bitMask;
|
||||
//Trim mask depending on byte, from left to right
|
||||
tempBitMask = (tempBitMask & (0xFF << 8 * (byteLength - 1 - z))) >> 8*(byteLength - 1 - z);
|
||||
|
||||
// Delete old bits
|
||||
binData[i * byteLength + z + getStorageAddress() - ramOffset] &= ~tempBitMask;
|
||||
|
||||
// Overwrite
|
||||
binData[i * byteLength + z + getStorageAddress() - ramOffset] |= output[z];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return binData;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public TableType getType() {
|
||||
return Table.TableType.TABLE_2D_MASKED_SWITCHABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
try {
|
||||
if (null == other) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (other == this) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!(other instanceof TableBitwiseSwitch)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Table2DMaskedSwitchable otherTable = (Table2DMaskedSwitchable) other;
|
||||
|
||||
if ((null == this.getName() && null == otherTable.getName())
|
||||
|| (this.getName().isEmpty() && otherTable.getName().isEmpty())) {
|
||||
;// Skip name compare if name is null or empty.
|
||||
} else if (!this.getName().equalsIgnoreCase(otherTable.getName())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.getDataSize() != otherTable.getDataSize()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this.bitMask == otherTable.bitMask) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
} catch (Exception ex) {
|
||||
// TODO: Log Exception.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Custom Button and Actionlistener
|
||||
*/
|
||||
class PresetButton extends JCheckBox{
|
||||
private static final long serialVersionUID = 1L;
|
||||
LinkedList<Integer> values; //Pointer to PresetEntry.data
|
||||
|
||||
public void setPresetData(LinkedList<Integer> list) {
|
||||
values = list;
|
||||
}
|
||||
|
||||
public void checkIfActive() {
|
||||
// Check if the radio button is current selected
|
||||
boolean found = true;
|
||||
|
||||
if (values != null) {
|
||||
for (int i = 0; i < getDataSize(); i++) {
|
||||
if(getDataSize() == values.size()) {
|
||||
if ((int) data[i].getBinValue() != values.get(i)) {
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
setSelected(found);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class PresetListener implements ActionListener{
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
PresetButton button = (PresetButton)event.getSource();
|
||||
|
||||
if(getDataSize() == button.values.size()) {
|
||||
for (int i = 0; i < getDataSize(); i++) {
|
||||
data[i].setBinValue(button.values.get(i));
|
||||
}
|
||||
}
|
||||
calcCellRanges();
|
||||
repaint();
|
||||
}
|
||||
}
|
||||
|
||||
//Java 9 Method
|
||||
private static int parseUnsignedInt(String s, int radix) throws NumberFormatException {
|
||||
if (s == null) {
|
||||
throw new NumberFormatException("null");
|
||||
}
|
||||
|
||||
int len = s.length();
|
||||
if (len > 0) {
|
||||
char firstChar = s.charAt(0);
|
||||
if (firstChar == '-') {
|
||||
throw new
|
||||
NumberFormatException(String.format("Illegal leading minus sign " +
|
||||
"on unsigned string %s.", s));
|
||||
} else {
|
||||
if (len <= 5 ||(radix == 10 && len <= 9) ) {
|
||||
return Integer.parseInt(s, radix);
|
||||
} else {
|
||||
long ell = Long.parseLong(s, radix);
|
||||
if ((ell & 0xffffffff00000000L) == 0) {
|
||||
return (int) ell;
|
||||
} else {
|
||||
throw new
|
||||
NumberFormatException(String.format("String value %s exceeds " + "range of unsigned int.", s));
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
throw new NumberFormatException(s);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
* Copyright (C) 2006-2020 RomRaider.com
|
||||
=======
|
||||
* Copyright (C) 2006-2019 RomRaider.com
|
||||
>>>>>>> Added XOR for single byte checksums. Added possibility of multiple checksums in file
|
||||
=======
|
||||
* Copyright (C) 2006-2020 RomRaider.com
|
||||
>>>>>>> Updated copyright. Switched to checkboxes for presets. Allowed multiple selection. Fixed saving bug. CChanged table name to 2DMaskedSwitchable
|
||||
*
|
||||
* 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 2 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, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
package com.romraider.maps.checksum;
|
||||
|
||||
import static com.romraider.xml.RomAttributeParser.parseByteValue;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.romraider.Settings;
|
||||
import com.romraider.util.HexUtil;
|
||||
|
||||
/**
|
||||
* This class implements the XOR single byte checksum validation and calculations
|
||||
* for some BMW non-engine ECU ROMs.
|
||||
*/
|
||||
public final class ChecksumBYTEXOR implements ChecksumManager {
|
||||
private static final String START = "start";
|
||||
private static final String END = "end";
|
||||
private static final String XORLOC = "xorloc";
|
||||
private int start;
|
||||
private int end;
|
||||
private int xorloc;
|
||||
private byte xort;
|
||||
|
||||
private boolean configured = false;
|
||||
|
||||
public ChecksumBYTEXOR() {}
|
||||
|
||||
@Override
|
||||
public void configure(Map<String, String> vars) {
|
||||
this.start = HexUtil.hexToInt(vars.get(START));
|
||||
this.end = HexUtil.hexToInt(vars.get(END));
|
||||
this.xorloc = HexUtil.hexToInt(vars.get(XORLOC));
|
||||
|
||||
this.configured = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean validate(byte[] binData) {
|
||||
if(!configured) {
|
||||
System.err.println("Checksum Manager was not configured before it was used for validating!");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
calculate(binData);
|
||||
final boolean valid = (xort == (byte)parseByteValue(binData, Settings.Endian.BIG, xorloc, 1, false));
|
||||
return valid;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void update(byte[] binData) {
|
||||
if(!configured)
|
||||
System.err.println("Checksum Manager was not configured before it was used for updating!");
|
||||
else {
|
||||
calculate(binData);
|
||||
binData[xorloc] = xort;
|
||||
}
|
||||
}
|
||||
|
||||
private void calculate(byte[] binData) {
|
||||
xort = 0;
|
||||
int dw = 0;
|
||||
for (int i = start; i < end; i += 1) {
|
||||
if ((i == xorloc)) continue;
|
||||
dw = (byte)parseByteValue(binData, Settings.Endian.BIG, i, 1, false);
|
||||
xort ^= dw;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
* Copyright (C) 2006-2020 RomRaider.com
|
||||
*
|
||||
* 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
|
||||
|
@ -119,6 +119,31 @@ public final class ByteUtil {
|
|||
return val;
|
||||
}
|
||||
|
||||
public static byte firstOneOfMask(int mask) {
|
||||
byte index = (byte) 0xFF;
|
||||
|
||||
for(byte i=0; i < 32; i++) {
|
||||
if(((mask >> i) & 1) == 1) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
public static byte lengthOfMask(int mask) {
|
||||
byte counter = 0;
|
||||
|
||||
for(byte i=0; i < 32; i++) {
|
||||
if(((mask >> i) & 1) == 1) {
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
return counter;
|
||||
}
|
||||
|
||||
private static int[] computeFailure(byte[] pattern) {
|
||||
int[] failure = new int[pattern.length];
|
||||
int j = 0;
|
||||
|
@ -134,4 +159,5 @@ public final class ByteUtil {
|
|||
return failure;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
* Copyright (C) 2006-2020 RomRaider.com
|
||||
*
|
||||
* 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
|
||||
|
@ -48,6 +48,7 @@ import com.romraider.maps.Table1D;
|
|||
import com.romraider.maps.Table2D;
|
||||
import com.romraider.maps.Table3D;
|
||||
import com.romraider.maps.TableBitwiseSwitch;
|
||||
import com.romraider.maps.Table2DMaskedSwitchable;
|
||||
import com.romraider.maps.TableSwitch;
|
||||
import com.romraider.maps.checksum.ChecksumFactory;
|
||||
import com.romraider.maps.checksum.ChecksumManager;
|
||||
|
@ -111,7 +112,7 @@ public final class DOMRomUnmarshaller {
|
|||
output.getRomID().setRamOffset(
|
||||
output.getRomID().getFileSize()
|
||||
- input.length);
|
||||
output.setChecksumManager(checksumManager);
|
||||
//output.addChecksumManager(checksumManager);
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
@ -238,6 +239,7 @@ public final class DOMRomUnmarshaller {
|
|||
} else if (n.getNodeName().equalsIgnoreCase("checksum")) {
|
||||
rom.getRomID().setChecksum(unmarshallAttribute(n, "type", ""));
|
||||
checksumManager = unmarshallChecksum(n);
|
||||
rom.addChecksumManager(checksumManager);
|
||||
|
||||
} else { /* unexpected element in Rom (skip) */
|
||||
}
|
||||
|
@ -415,7 +417,10 @@ public final class DOMRomUnmarshaller {
|
|||
} else if (unmarshallAttribute(tableNode, "type", "unknown")
|
||||
.equalsIgnoreCase("BitwiseSwitch")) {
|
||||
table = new TableBitwiseSwitch();
|
||||
|
||||
}
|
||||
else if (unmarshallAttribute(tableNode, "type", "unknown")
|
||||
.equalsIgnoreCase("2DMaskedSwitchable")) {
|
||||
table = new Table2DMaskedSwitchable();
|
||||
} else {
|
||||
throw new XMLParseException("Error loading table, "
|
||||
+ tableNode.getAttributes().getNamedItem("name"));
|
||||
|
@ -426,7 +431,6 @@ public final class DOMRomUnmarshaller {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
// unmarshall table attributes
|
||||
final String tn = unmarshallAttribute(tableNode, "name", table.getName());
|
||||
table.setName(tn);
|
||||
|
@ -464,6 +468,7 @@ public final class DOMRomUnmarshaller {
|
|||
"storageaddress",
|
||||
String.valueOf(table.getStorageAddress()))));
|
||||
}
|
||||
|
||||
table.setDescription(unmarshallAttribute(tableNode, "description",
|
||||
table.getDescription()));
|
||||
table.setDataSize(unmarshallAttribute(tableNode, "sizey",
|
||||
|
@ -477,6 +482,7 @@ public final class DOMRomUnmarshaller {
|
|||
table.setLogParam(unmarshallAttribute(tableNode, "logparam",
|
||||
table.getLogParam()));
|
||||
|
||||
|
||||
if (table.getType() == Table.TableType.TABLE_3D) {
|
||||
((Table3D) table).setSwapXY(unmarshallAttribute(tableNode,
|
||||
"swapxy", ((Table3D) table).getSwapXY()));
|
||||
|
@ -490,6 +496,11 @@ public final class DOMRomUnmarshaller {
|
|||
((Table3D) table).getSizeY()));
|
||||
}
|
||||
|
||||
if (table.getType() == Table.TableType.TABLE_2D_MASKED_SWITCHABLE) {
|
||||
((Table2DMaskedSwitchable) table).setStringMask(
|
||||
unmarshallAttribute(tableNode, "mask", "FFFFFFFF"));
|
||||
}
|
||||
|
||||
Node n;
|
||||
NodeList nodes = tableNode.getChildNodes();
|
||||
|
||||
|
@ -499,7 +510,7 @@ public final class DOMRomUnmarshaller {
|
|||
if (n.getNodeType() == ELEMENT_NODE) {
|
||||
if (n.getNodeName().equalsIgnoreCase("table")) {
|
||||
|
||||
if (table.getType() == Table.TableType.TABLE_2D) { // if table is 2D,
|
||||
if (table.getType() == Table.TableType.TABLE_2D || table.getType() == Table.TableType.TABLE_2D_MASKED_SWITCHABLE) { // if table is 2D,
|
||||
// parse axis
|
||||
|
||||
if (RomAttributeParser
|
||||
|
@ -580,17 +591,17 @@ public final class DOMRomUnmarshaller {
|
|||
unmarshallAttribute(n, "name", ""),
|
||||
unmarshallAttribute(n, "data", "0.0"));
|
||||
|
||||
} else if (n.getNodeName().equalsIgnoreCase("bit")) {
|
||||
((TableBitwiseSwitch) table).setValues(
|
||||
unmarshallAttribute(n, "name", ""),
|
||||
unmarshallAttribute(n, "position", "0"));
|
||||
} else if (n.getNodeName().equalsIgnoreCase("maskedPreset")) {
|
||||
((Table2DMaskedSwitchable) table).setPredefinedOption(
|
||||
unmarshallAttribute(n, "presetName", ""),
|
||||
unmarshallAttribute(n, "maskedData", "0")
|
||||
|
||||
);
|
||||
} else { /* unexpected element in Table (skip) */
|
||||
}
|
||||
} else { /* unexpected node-type in Table (skip) */
|
||||
}
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
|
@ -673,11 +684,12 @@ public final class DOMRomUnmarshaller {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!tableNames.containsKey(name) && address > 0) {
|
||||
//Why cant the address not be zero?
|
||||
if (!tableNames.containsKey(name) && address >= 0) {
|
||||
tableNames.put(name, address);
|
||||
}
|
||||
else if (tableNames.containsKey(name)) {
|
||||
if (tableNames.get(name) < 1 && address > 0) {
|
||||
if (tableNames.get(name) < 1 && address >= 0) {
|
||||
tableNames.put(name, address);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
/*
|
||||
* RomRaider Open-Source Tuning, Logging and Reflashing
|
||||
* Copyright (C) 2006-2018 RomRaider.com
|
||||
<<<<<<< HEAD
|
||||
<<<<<<< HEAD
|
||||
* Copyright (C) 2006-2020 RomRaider.com
|
||||
=======
|
||||
* Copyright (C) 2006-2019 RomRaider.com
|
||||
>>>>>>> Added XOR for single byte checksums. Added possibility of multiple checksums in file
|
||||
=======
|
||||
* Copyright (C) 2006-2020 RomRaider.com
|
||||
>>>>>>> Updated copyright. Switched to checkboxes for presets. Allowed multiple selection. Fixed saving bug. CChanged table name to 2DMaskedSwitchable
|
||||
*
|
||||
* 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
|
||||
|
@ -27,6 +35,7 @@ import java.nio.ByteOrder;
|
|||
|
||||
import com.romraider.Settings;
|
||||
import com.romraider.maps.Table;
|
||||
import com.romraider.util.ByteUtil;
|
||||
|
||||
public final class RomAttributeParser {
|
||||
|
||||
|
@ -115,6 +124,16 @@ public final class RomAttributeParser {
|
|||
}
|
||||
}
|
||||
|
||||
//This assumes the bits inside the mask aren't spread. OK = 11110000, Not OK = 11001100
|
||||
|
||||
public static long parseByteValueMasked(byte[] input, Settings.Endian endian, int address, int length, boolean signed, int mask) throws ArrayIndexOutOfBoundsException, IndexOutOfBoundsException {
|
||||
long tempValue = parseByteValue(input,endian,address,length,signed) & mask;
|
||||
|
||||
byte index = ByteUtil.firstOneOfMask(mask);
|
||||
|
||||
return tempValue >> index;
|
||||
}
|
||||
|
||||
public static long parseByteValue(byte[] input, Settings.Endian endian, int address, int length, boolean signed) throws ArrayIndexOutOfBoundsException, IndexOutOfBoundsException {
|
||||
try {
|
||||
long output = 0L;
|
||||
|
@ -230,6 +249,9 @@ public final class RomAttributeParser {
|
|||
else if (input.substring(input.length() - 2).equalsIgnoreCase("mb")) {
|
||||
return Integer.parseInt(input.substring(0, input.length() - 2)) * 1024 * 1024;
|
||||
}
|
||||
else if (input.substring(input.length() - 1).equalsIgnoreCase("b")) {
|
||||
return Integer.parseInt(input.substring(0, input.length() - 1));
|
||||
}
|
||||
throw new NumberFormatException();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue