/*
* BEValue - Holds different types that a bencoded byte array can represent.
* Copyright (C) 2003 Mark J. Wielaard
*
* This file is part of Snark.
*
* 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, 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., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*
* Revised by Stephen L. Reed, Dec 22, 2009.
* Reformatted, fixed Checkstyle, Findbugs and PMD violations, and substituted Log4J logger
* for consistency with the Texai project.
*/
package org.texai.torrent.bencode;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Map;
/** Holds different types that a bencoded byte array can represent, which is a byte[], Number, List or Map (String --> BEValue).
*
* You need to call the correct get method to get the correct java type object. If the BEValue wasn't actually
* of the requested type you will get a InvalidBEncodingException.
*
* @author Mark Wielaard (mark@klomp.org)
*/
public class BEValue {
/** the value */
private final Object value;
/** Constructs a new BEValue instance.
*
* @param value the byte array value
*/
public BEValue(final byte[] value) {
this.value = value;
}
/** Constructs a new BEValue instance.
*
* @param value the number value
*/
public BEValue(final Number value) {
this.value = value;
}
/** Constructs a new BEValue instance.
*
* @param value the BEValue list value
*/
public BEValue(final List<BEValue> value) {
this.value = value;
}
/** Constructs a new BEValue instance.
*
* @param value the BEValue map value
*/
public BEValue(final Map<String, BEValue> value) {
this.value = value;
}
/** Gets the value.
*
* @return the value
*/
public Object getValue() {
return value;
}
/** Returns this BEValue as a String. This operation only succeeds when the
* BEValue is a byte[], otherwise it will throw a InvalidBEncodingException.
* The byte[] will be interpreted as UTF-8 encoded characters.
*
* @return this BEValue as a String
* @throws InvalidBEncodingException when the BEValue is not a byte[]
*/
public String getString() throws InvalidBEncodingException {
try {
return new String(getBytes(), "UTF-8");
} catch (ClassCastException cce) {
throw new InvalidBEncodingException(cce.toString()); // NOPMD
} catch (UnsupportedEncodingException uee) {
throw new InternalError(uee.toString()); // NOPMD
}
}
/** Returns this BEValue as a byte[]. This operation only succeeds when the
* BEValue is actually a byte[], otherwise it will throw a
* InvalidBEncodingException.
*
* @return this BEValue as a byte[]
* @throws InvalidBEncodingException when the BEValue is not a byte[]
*/
public byte[] getBytes() throws InvalidBEncodingException {
try {
return (byte[]) value;
} catch (ClassCastException cce) {
throw new InvalidBEncodingException(cce.toString()); // NOPMD
}
}
/** Returns this BEValue as a Number. This operation only succeeds when the
* BEValue is actually a Number, otherwise it will throw a
* InvalidBEncodingException.
*
* @return this BEValue as a Number
* @throws InvalidBEncodingException when the BEValue is not a number
*/
public Number getNumber() throws InvalidBEncodingException {
try {
return (Number) value;
} catch (ClassCastException cce) {
throw new InvalidBEncodingException(cce.toString()); // NOPMD
}
}
/** Returns this BEValue as int. This operation only succeeds when the
* BEValue is actually a Number, otherwise it will throw a
* InvalidBEncodingException. The returned int is the result of
* <code>Number.intValue()</code>.
*
* @return this BEValue as int
* @throws InvalidBEncodingException when the BEValue is not a number
*/
public int getInt() throws InvalidBEncodingException {
return getNumber().intValue();
}
/** Returns this BEValue as long. This operation only succeeds when the
* BEValue is actually a Number, otherwise it will throw a
* InvalidBEncodingException. The returned long is the result of
* <code>Number.longValue()</code>.
*
* @return this BEValue as long
* @throws InvalidBEncodingException when the BEValue is not a number
*/
public long getLong() throws InvalidBEncodingException {
return getNumber().longValue();
}
/**
* Returns this BEValue as a List of BEValues. This operation only succeeds
* when the BEValue is actually a List, otherwise it will throw a
* InvalidBEncodingException.
*
* @return this BEValue as a List of BEValues
* @throws InvalidBEncodingException when the BEValue is not a list of BEValues
*/
@SuppressWarnings("unchecked")
public List<BEValue> getList() throws InvalidBEncodingException {
try {
return (List<BEValue>) value;
} catch (ClassCastException cce) {
final String errorMessage = value.toString() + "(" + value.getClass().getName() + ") cannot be cast to List<BEValue>";
throw new InvalidBEncodingException(cce.getMessage() + "\n" + errorMessage); // NOPMD
}
}
/** Returns this BEValue as a Map of BEValue keys and BEValue values. This
* operation only succeeds when the BEValue is actually a Map, otherwise it
* will throw a InvalidBEncodingException.
*
* @return this BEValue as a Map of BEValue keys and BEValue values
* @throws InvalidBEncodingException when value is not a map
*/
@SuppressWarnings("unchecked")
public Map<String, BEValue> getMap() throws InvalidBEncodingException {
try {
return (Map<String, BEValue>) value;
} catch (ClassCastException cce) {
throw new InvalidBEncodingException(cce.toString()); // NOPMD
}
}
/** Returns a string representation of this object.
*
* @return a string representation of this object
*/
@Override
public String toString() {
String valueString;
if (value instanceof byte[]) {
final byte[] byteArray = (byte[]) value;
// XXX - Stupid heuristic...
if (byteArray.length <= 12) {
valueString = new String(byteArray);
} else {
valueString = "bytes, length:" + byteArray.length;
}
} else {
valueString = value.toString();
}
return "BEValue[" + valueString + "]";
}
}