/* This file is part of jpcsp. Jpcsp 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. Jpcsp 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 Jpcsp. If not, see <http://www.gnu.org/licenses/>. */ package jpcsp.HLE.kernel.types; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.Date; import java.util.LinkedList; import java.util.List; import jpcsp.HLE.TPointer; import jpcsp.util.Utilities; public class SceNpTicket extends pspAbstractMemoryMappedStructure { public static final int NUMBER_PARAMETERS = 12; public int version; public int size; public int unknown; public int sizeParams; public List<TicketParam> parameters = new LinkedList<SceNpTicket.TicketParam>(); public byte[] unknownBytes; public static class TicketParam { public static final int PARAM_TYPE_NULL = 0; public static final int PARAM_TYPE_INT = 1; public static final int PARAM_TYPE_LONG = 2; public static final int PARAM_TYPE_STRING = 4; public static final int PARAM_TYPE_DATE = 7; public static final int PARAM_TYPE_STRING_ASCII = 8; public int type; private byte[] value; public TicketParam(int type, byte[] value) { this.type = type; this.value = value; } public int getType() { return type; } private int getIntValue(int offset) { return Utilities.endianSwap32(Utilities.readUnaligned32(value, offset)); } public int getIntValue() { return getIntValue(0); } public long getLongValue() { return (((long) getIntValue(0)) << 32) | (getIntValue(4) & 0xFFFFFFFFL); } public String getStringValue() { int length = value.length; for (int i = 0; i < value.length; i++) { if (value[i] == (byte) 0) { length = i; break; } } return new String(value, 0, length); } public byte[] getBytesValue() { return value; } public Date getDateValue() { return new Date(getLongValue()); } public void writeForPSP(TPointer buffer) { switch (type) { case PARAM_TYPE_INT: // This value is written in PSP endianness buffer.setValue32(getIntValue()); break; case PARAM_TYPE_DATE: case PARAM_TYPE_LONG: // This value is written in PSP endianness buffer.setValue64(getLongValue()); break; case PARAM_TYPE_STRING: case PARAM_TYPE_STRING_ASCII: int length = value.length; if (length >= 256) { length = 255; // PSP returns maximum 255 bytes } Utilities.writeBytes(buffer.getAddress(), length, value, 0); // Add trailing 0 buffer.setValue8(length, (byte) 0); break; default: // Copy nothing break; } } @Override public String toString() { switch (type) { case PARAM_TYPE_INT: return String.format("0x%X", getIntValue()); case PARAM_TYPE_STRING_ASCII: case PARAM_TYPE_STRING: return getStringValue(); case PARAM_TYPE_DATE: return getDateValue().toString(); case PARAM_TYPE_NULL: return "null"; case PARAM_TYPE_LONG: return String.format("0x%16X", getLongValue()); } return String.format("type=%d, value=%s", type, Utilities.getMemoryDump(value, 0, value.length)); } } @Override protected void read() { version = read32(); size = endianSwap32(read32()); unknown = endianSwap16((short) read16()); sizeParams = endianSwap16((short) read16()); parameters.clear(); for (int i = 0; i < NUMBER_PARAMETERS; i++) { int type = endianSwap16((short) read16()); int length = endianSwap16((short) read16()); byte[] value = new byte[length]; read8Array(value); TicketParam ticketParam = new TicketParam(type, value); parameters.add(ticketParam); } unknownBytes = new byte[size - getOffset() + 8]; read8Array(unknownBytes); } @Override protected void write() { write32(version); write32(endianSwap32(size)); write16((short) endianSwap16((short) unknown)); write16((short) endianSwap16((short) sizeParams)); for (TicketParam ticketParam : parameters) { write16((short) endianSwap16((short) ticketParam.getType())); byte[] value = ticketParam.getBytesValue(); write16((short) endianSwap16((short) value.length)); write8Array(value); } write8Array(unknownBytes); } public byte[] toByteArray() { byte[] bytes = new byte[sizeof()]; ByteBuffer b = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); b.putInt(version); b.putInt(endianSwap32(size)); b.putShort((short) endianSwap16((short) unknown)); b.putShort((short) endianSwap16((short) sizeParams)); for (TicketParam ticketParam : parameters) { b.putShort((short) endianSwap16((short) ticketParam.getType())); byte[] value = ticketParam.getBytesValue(); b.putShort((short) endianSwap16((short) value.length)); b.put(value); } b.put(unknownBytes); return bytes; } public void read(byte[] bytes, int offset, int length) { ByteBuffer b = ByteBuffer.wrap(bytes, offset, length).order(ByteOrder.LITTLE_ENDIAN); version = b.getInt(); size = endianSwap32(b.getInt()); unknown = endianSwap16(b.getShort()); sizeParams = endianSwap16(b.getShort()); int readSize = 12; parameters.clear(); for (int i = 0; i < NUMBER_PARAMETERS; i++) { int type = endianSwap16(b.getShort()); int valueLength = endianSwap16(b.getShort()); byte[] value = new byte[valueLength]; b.get(value); readSize += 4 + valueLength; TicketParam ticketParam = new TicketParam(type, value); parameters.add(ticketParam); } unknownBytes = new byte[size - readSize + 8]; b.get(unknownBytes); } @Override public int sizeof() { return size + 8; } @Override public String toString() { StringBuilder s = new StringBuilder(); s.append(String.format("version=0x%08X", version)); s.append(String.format(", size=0x%X", size)); s.append(String.format(", unknown=0x%X", unknown)); for (int i = 0; i < parameters.size(); i++) { TicketParam param = parameters.get(i); s.append(String.format(", param#%d=%s", i, param)); } s.append(String.format(", unknownBytes: %s", Utilities.getMemoryDump(unknownBytes, 0, unknownBytes.length))); return s.toString(); } }