/*
* Copyright 2010, 2011, 2012 mapsforge.org
*
* This program is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free Software
* Foundation, either version 3 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.mapsforge.map.writer;
import java.security.InvalidParameterException;
/**
* This class converts numbers to byte arrays.
*/
public final class Serializer {
/**
* Converts a signed int to a byte array.
* <p>
* The byte order is big-endian.
*
* @param value
* the int value.
* @return an array with four bytes.
*/
public static byte[] getBytes(int value) {
return new byte[] { (byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) value };
}
/**
* Converts a signed long to a byte array.
* <p>
* The byte order is big-endian.
*
* @param value
* the long value.
* @return an array with eight bytes.
*/
public static byte[] getBytes(long value) {
return new byte[] { (byte) (value >> 56), (byte) (value >> 48), (byte) (value >> 40), (byte) (value >> 32),
(byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8), (byte) value };
}
/**
* Converts a signed short to a byte array.
* <p>
* The byte order is big-endian.
*
* @param value
* the short value.
* @return an array with two bytes.
*/
public static byte[] getBytes(short value) {
return new byte[] { (byte) (value >> 8), (byte) value };
}
/**
* Converts the lowest five bytes of an unsigned long to a byte array.
* <p>
* The byte order is big-endian.
*
* @param value
* the long value, must not be negative.
* @return an array with five bytes.
*/
public static byte[] getFiveBytes(long value) {
if (value < 0) {
throw new IllegalArgumentException("negative value not allowed: " + value);
} else if (value > 1099511627775L) {
throw new IllegalArgumentException("value out of range: " + value);
}
return new byte[] { (byte) (value >> 32), (byte) (value >> 24), (byte) (value >> 16), (byte) (value >> 8),
(byte) value };
}
/**
* Converts a signed int to a variable length byte array.
* <p>
* The first bit is for continuation info, the other six (last byte) or seven (all other bytes) bits for data. The
* second bit in the last byte indicates the sign of the number.
*
* @param value
* the int value.
* @return an array with 1-5 bytes.
*/
public static byte[] getVariableByteSigned(int value) {
long absValue = Math.abs((long) value);
if (absValue < 64) { // 2^6
// encode the number in a single byte
if (value < 0) {
return new byte[] { (byte) (absValue | 0x40) };
}
return new byte[] { (byte) absValue };
} else if (absValue < 8192) { // 2^13
// encode the number in two bytes
if (value < 0) {
return new byte[] { (byte) (absValue | 0x80), (byte) ((absValue >> 7) | 0x40) };
}
return new byte[] { (byte) (absValue | 0x80), (byte) (absValue >> 7) };
} else if (absValue < 1048576) { // 2^20
// encode the number in three bytes
if (value < 0) {
return new byte[] { (byte) (absValue | 0x80), (byte) ((absValue >> 7) | 0x80),
(byte) ((absValue >> 14) | 0x40) };
}
return new byte[] { (byte) (absValue | 0x80), (byte) ((absValue >> 7) | 0x80), (byte) (absValue >> 14) };
} else if (absValue < 134217728) { // 2^27
// encode the number in four bytes
if (value < 0) {
return new byte[] { (byte) (absValue | 0x80), (byte) ((absValue >> 7) | 0x80),
(byte) ((absValue >> 14) | 0x80), (byte) ((absValue >> 21) | 0x40) };
}
return new byte[] { (byte) (absValue | 0x80), (byte) ((absValue >> 7) | 0x80),
(byte) ((absValue >> 14) | 0x80), (byte) (absValue >> 21) };
} else {
// encode the number in five bytes
if (value < 0) {
return new byte[] { (byte) (absValue | 0x80), (byte) ((absValue >> 7) | 0x80),
(byte) ((absValue >> 14) | 0x80), (byte) ((absValue >> 21) | 0x80),
(byte) ((absValue >> 28) | 0x40) };
}
return new byte[] { (byte) (absValue | 0x80), (byte) ((absValue >> 7) | 0x80),
(byte) ((absValue >> 14) | 0x80), (byte) ((absValue >> 21) | 0x80), (byte) (absValue >> 28) };
}
}
/**
* Converts an unsigned int to a variable length byte array.
* <p>
* The first bit is for continuation info, the other seven bits for data.
*
* @param value
* the int value, must not be negative.
* @return an array with 1-5 bytes.
*/
public static byte[] getVariableByteUnsigned(int value) {
if (value < 0) {
throw new InvalidParameterException("negative value not allowed: " + value);
} else if (value < 128) { // 2^7
// encode the number in a single byte
return new byte[] { (byte) value };
} else if (value < 16384) { // 2^14
// encode the number in two bytes
return new byte[] { (byte) (value | 0x80), (byte) (value >> 7) };
} else if (value < 2097152) { // 2^21
// encode the number in three bytes
return new byte[] { (byte) (value | 0x80), (byte) ((value >> 7) | 0x80), (byte) (value >> 14) };
} else if (value < 268435456) { // 2^28
// encode the number in four bytes
return new byte[] { (byte) (value | 0x80), (byte) ((value >> 7) | 0x80), (byte) ((value >> 14) | 0x80),
(byte) (value >> 21) };
} else {
// encode the number in five bytes
return new byte[] { (byte) (value | 0x80), (byte) ((value >> 7) | 0x80), (byte) ((value >> 14) | 0x80),
(byte) ((value >> 21) | 0x80), (byte) (value >> 28) };
}
}
private Serializer() {
throw new IllegalStateException();
}
}