// Near Infinity - An Infinity Engine Browser and Editor
// Copyright (C) 2001 - 2005 Jon Olav Hauglid
// See LICENSE.txt for license information
package org.infinity.datatype;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.util.Locale;
import org.infinity.resource.StructEntry;
public class DecNumber extends Datatype implements InlineEditable, IsNumeric
{
private long number;
private boolean signed;
public DecNumber(ByteBuffer buffer, int offset, int length, String name)
{
this(null, buffer, offset, length, name, true);
}
public DecNumber(ByteBuffer buffer, int offset, int length, String name, boolean signed)
{
this(null, buffer, offset, length, name, signed);
}
public DecNumber(StructEntry parent, ByteBuffer buffer, int offset, int length, String name)
{
this(parent, buffer, offset, length, name, true);
}
public DecNumber(StructEntry parent, ByteBuffer buffer, int offset, int length, String name, boolean signed)
{
super(parent, offset, length, name);
this.number = 0L;
this.signed = signed;
read(buffer, offset);
}
// --------------------- Begin Interface InlineEditable ---------------------
@Override
public boolean update(Object value)
{
try {
number = parseNumber(value, getSize(), signed, true);
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
// --------------------- End Interface InlineEditable ---------------------
// --------------------- Begin Interface Writeable ---------------------
@Override
public void write(OutputStream os) throws IOException
{
writeLong(os, number);
}
// --------------------- End Interface Writeable ---------------------
// --------------------- Begin Interface Readable ---------------------
@Override
public int read(ByteBuffer buffer, int offset)
{
buffer.position(offset);
switch (getSize()) {
case 1:
if (signed) {
number = buffer.get();
} else {
number = buffer.get() & 0xff;
}
break;
case 2:
if (signed) {
number = buffer.getShort();
} else {
number = buffer.getShort() & 0xffff;
}
break;
case 4:
if (signed) {
number = buffer.getInt();
} else {
number = buffer.getInt() & 0xffffffff;
}
break;
default:
throw new IllegalArgumentException();
}
return offset + getSize();
}
// --------------------- End Interface Readable ---------------------
// --------------------- Begin Interface IsNumeric ---------------------
@Override
public long getLongValue()
{
return number;
}
@Override
public int getValue()
{
return (int)number;
}
// --------------------- End Interface IsNumeric ---------------------
public void incValue(long value)
{
number += value;
}
public void setValue(long value)
{
number = value;
}
@Override
public String toString()
{
return Long.toString(number);
}
/** Attempts to parse the specified string into a decimal or, optionally, hexadecimal number. */
static long parseNumber(Object value, int size, boolean negativeAllowed, boolean hexAllowed) throws Exception
{
if (value == null) {
throw new NullPointerException();
}
String s = value.toString().trim().toLowerCase(Locale.ENGLISH);
int radix = 10;
if (hexAllowed && s.startsWith("0x")) {
s = s.substring(2);
radix = 16;
} else if (hexAllowed && s.endsWith("h")) {
s = s.substring(0, s.length() - 1).trim();
radix = 16;
}
long newNumber = Long.parseLong(s, radix);
long discard = negativeAllowed ? 1L : 0L;
long maxNum = (1L << ((long)size*8L - discard)) - 1L;
long minNum = negativeAllowed ? -(maxNum+1L) : 0;
if (newNumber > maxNum || newNumber < minNum) {
throw new NumberFormatException("Number out of range: " + newNumber);
}
return newNumber;
}
}