/* * RomRaider Open-Source Tuning, Logging and Reflashing * Copyright (C) 2006-2017 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. */ // Parses attributes from ROM XML package com.romraider.xml; import java.nio.BufferOverflowException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import com.romraider.Settings; public final class RomAttributeParser { private RomAttributeParser() { } public static int parseEndian(String input) { if (input.equalsIgnoreCase("big") || input.equalsIgnoreCase(String.valueOf(Settings.ENDIAN_BIG))) { return Settings.ENDIAN_BIG; } else if (input.equalsIgnoreCase("little") || input.equalsIgnoreCase(String.valueOf(Settings.ENDIAN_LITTLE))) { return Settings.ENDIAN_LITTLE; } else { return Settings.ENDIAN_LITTLE; } } public static int parseHexString(String input) { if (input.equals("0")) { return 0; } else if (input.length() > 2 && input.substring(0, 2).equalsIgnoreCase("0x")) { return Integer.parseInt(input.substring(2), 16); } else { return Integer.parseInt(input, 16); } } public static int parseStorageType(String input) { if (input.equalsIgnoreCase("movi20")) { // when data is in MOVI20 instruction return Settings.STORAGE_TYPE_MOVI20; } else if (input.equalsIgnoreCase("movi20s")) { // when data is in MOVI20 instruction return Settings.STORAGE_TYPE_MOVI20S; } else if (input.equalsIgnoreCase("float")) { return Settings.STORAGE_TYPE_FLOAT; } else if (input.startsWith("uint")) { return Integer.parseInt(input.substring(4)) / 8; } else if (input.startsWith("int")) { return Integer.parseInt(input.substring(3)) / 8; } else { return Integer.parseInt(input); } } public static boolean parseStorageDataSign(String input) { if (input.toLowerCase().startsWith("int") || input.toLowerCase().startsWith("movi20")) { // when data is in MOVI20 instruction return true; } else { return false; } } public static int parseScaleType(String input) { if (input.equalsIgnoreCase("inverse")) { return Settings.INVERSE; } else { return Settings.LINEAR; } } public static int parseTableType(String input) { if (input.equalsIgnoreCase("3D") || input.equalsIgnoreCase(String.valueOf(Settings.TABLE_3D))) { return Settings.TABLE_3D; } else if (input.equalsIgnoreCase("2D") || input.equalsIgnoreCase(String.valueOf(Settings.TABLE_2D))) { return Settings.TABLE_2D; } else if (input.equalsIgnoreCase("X Axis") || input.equalsIgnoreCase("Static X Axis") || input.equalsIgnoreCase(String.valueOf(Settings.TABLE_X_AXIS))) { return Settings.TABLE_X_AXIS; } else if (input.equalsIgnoreCase("Y Axis") || input.equalsIgnoreCase("Static Y Axis") || input.equalsIgnoreCase(String.valueOf(Settings.TABLE_Y_AXIS))) { return Settings.TABLE_Y_AXIS; } else { return Settings.TABLE_1D; } } public static long parseByteValue(byte[] input, int endian, int address, int length, boolean signed) throws ArrayIndexOutOfBoundsException, IndexOutOfBoundsException { try { long output = 0L; int llength = length; if (length == Settings.STORAGE_TYPE_MOVI20 || length == Settings.STORAGE_TYPE_MOVI20S) { llength = 3; } final ByteBuffer bb = ByteBuffer.wrap(input, address, llength); if (endian == Settings.ENDIAN_LITTLE) { bb.order(ByteOrder.LITTLE_ENDIAN); } switch (length) { case 1: output = bb.get(); break; case 2: output = bb.getShort(); break; case 4: output = bb.getInt(); break; case Settings.STORAGE_TYPE_MOVI20: case Settings.STORAGE_TYPE_MOVI20S: bb.position(bb.position()-1); output = getMovi20(bb.getInt()); break; } if (!signed) { switch (length) { case 1: output = output & 0xff; break; case 2: output = output & 0xffff; break; case 4: output = output & 0xffffffffL; break; } } return output; } catch (IndexOutOfBoundsException ex) { throw new IndexOutOfBoundsException(); } } // when data is in MOVI20 instruction private static int getMovi20(int value) { final int shift = value & 0x00010000; value = ((value & 0x00f00000) >>> 4) + (value & 0x0000FFFF); if ((value & 0x00080000) > 0) { value = (value | 0xfff00000); } if (shift > 0) { //MOVI20S return (value << 8); } return value; } public static byte[] parseIntegerValue(int input, int endian, int length) { try { int llength = length; if (length == Settings.STORAGE_TYPE_MOVI20 || length == Settings.STORAGE_TYPE_MOVI20S) { llength = 4; } final ByteBuffer bb = ByteBuffer.allocate(llength); if (endian == Settings.ENDIAN_LITTLE) { bb.order(ByteOrder.LITTLE_ENDIAN); } switch (length) { case 1: bb.put((byte) input); break; case 2: bb.putShort((short) input); break; case 4: bb.putInt(input); break; case Settings.STORAGE_TYPE_MOVI20: return parseMovi20(bb.putInt(input).array(), length); case Settings.STORAGE_TYPE_MOVI20S: return parseMovi20(bb.putInt(input>>8).array(), length); } return bb.array(); } catch (BufferOverflowException ex) { throw new BufferOverflowException(); } } // when data is in MOVI20 instruction private static byte[] parseMovi20(byte[] bytes, int length) { final byte[] output = {0,0,0}; output[0] = (byte) (bytes[1] << 4); if (length == Settings.STORAGE_TYPE_MOVI20S) { //MOVI20S output[0] = (byte) ((bytes[1] << 4) | 0x01); } output[1] = bytes[2]; output[2] = bytes[3]; return output; } public static int parseFileSize(String input) throws NumberFormatException { try { return Integer.parseInt(input); } catch (NumberFormatException ex) { if (input.substring(input.length() - 2).equalsIgnoreCase("kb")) { return Integer.parseInt(input.substring(0, input.length() - 2)) * 1024; } else if (input.substring(input.length() - 2).equalsIgnoreCase("mb")) { return Integer.parseInt(input.substring(0, input.length() - 2)) * 1024 * 1024; } throw new NumberFormatException(); } } public static byte[] floatToByte(float input, int endian, int memModelEndian) { byte[] output = new byte[4]; ByteBuffer bb = ByteBuffer.wrap(output, 0, 4); if (memModelEndian == Settings.ENDIAN_LITTLE) { bb.order(ByteOrder.LITTLE_ENDIAN); } else if (memModelEndian == Settings.ENDIAN_BIG) { bb.order(ByteOrder.BIG_ENDIAN); } else { // this case corrects improperly defined float table endian in legacy definition files if (endian == Settings.ENDIAN_LITTLE) { bb.order(ByteOrder.BIG_ENDIAN); } } bb.putFloat(input); return bb.array(); } public static float byteToFloat(byte[] input, int endian, int memModelEndian) { ByteBuffer bb = ByteBuffer.wrap(input, 0, 4); if (memModelEndian == Settings.ENDIAN_LITTLE) { bb.order(ByteOrder.LITTLE_ENDIAN); } else if (memModelEndian == Settings.ENDIAN_BIG) { bb.order(ByteOrder.BIG_ENDIAN); } else { // this case corrects improperly defined float table endian in legacy definition files if (endian == Settings.ENDIAN_LITTLE) { bb.order(ByteOrder.BIG_ENDIAN); } } return bb.getFloat(); } }