/** * Copyright (c) 2013, Will Szumski * * This file is part of formicidae. * * formicidae 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. * * formicidae 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 formicidae. If not, see <http://www.gnu.org/licenses/>. */ package org.cowboycoders.ant.utils; import java.math.BigInteger; import java.nio.ByteBuffer; import java.util.Arrays; /** * Various BigInteger utils. * @author will * */ public class BigIntUtils { private BigIntUtils() {} public static int NUMBER_OF_BYTES_BYTE = 1; public static int NUMBER_OF_BYTES_SHORT= Short.SIZE / Byte.SIZE; public static int NUMBER_OF_BYTES_INT= Integer.SIZE / Byte.SIZE; public static int NUMBER_OF_BYTES_LONG = Long.SIZE / Byte.SIZE; public static BigInteger convertUnsignedByte(byte value) { if (value >= 0) { return convertByte(value); } return new BigInteger(ByteBuffer.allocate(NUMBER_OF_BYTES_BYTE + 1).put(1,value).array()); } public static BigInteger convertByte(byte value) { return new BigInteger(ByteBuffer.allocate(NUMBER_OF_BYTES_BYTE).put(value).array()); } public static BigInteger convertShort(short value) { return new BigInteger(ByteBuffer.allocate(NUMBER_OF_BYTES_SHORT).putShort(value).array()); } public static BigInteger convertUnsignedShort(short value) { if (value >= 0) { return convertShort(value); } return new BigInteger(ByteBuffer.allocate(NUMBER_OF_BYTES_SHORT + 1).putShort(1,value).array()); } public static BigInteger convertInt(int value) { return new BigInteger(ByteBuffer.allocate(NUMBER_OF_BYTES_INT).putInt(value).array()); } public static BigInteger convertUnsignedInt(int value) { if (value >= 0) { return convertInt(value); } return new BigInteger(ByteBuffer.allocate(NUMBER_OF_BYTES_INT + 1).putInt(1,value).array()); } public static BigInteger convertLong(long value) { return new BigInteger(ByteBuffer.allocate(NUMBER_OF_BYTES_LONG).putLong(value).array()); } public static BigInteger convertUnsignedLong(long value) { if (value >= 0) { return convertLong(value); } return new BigInteger(ByteBuffer.allocate(NUMBER_OF_BYTES_LONG + 1).putLong(1,value).array()); } public static byte [] toByteArrayLittleEndian(BigInteger bi) { byte [] extractedBytes = bi.toByteArray(); byte [] reversed = ByteUtils.reverseArray(extractedBytes); return reversed; } public static byte [] toByteArrayUnsigned(BigInteger bi) { byte [] extractedBytes = bi.toByteArray(); int skipped = 0; boolean skip = true; for (byte b : extractedBytes) { boolean signByte = b == (byte)0x00; if (skip && signByte) { skipped++; continue; } else if (skip) { skip = false; } } extractedBytes = Arrays.copyOfRange(extractedBytes, skipped, extractedBytes.length); return extractedBytes; } public static byte [] toByteArrayLittleEndianUnsigned(BigInteger bi) { byte [] extractedBytes = toByteArrayUnsigned(bi); byte [] reversed = ByteUtils.reverseArray(extractedBytes); return reversed; } public static BigInteger newLittleEndian(byte [] bytes) { byte [] constructionBytes = ByteUtils.reverseArray(bytes); return new BigInteger(constructionBytes); } /** * Used on BigIntegers known to fit into x number of bytes. * * Discards more significant bytes. * * {@link BigIntUtils#NUMBER_OF_BYTES_BYTE} * {@link BigIntUtils#NUMBER_OF_BYTES_SHORT} * {@link BigIntUtils#NUMBER_OF_BYTES_INT} * {@link BigIntUtils#NUMBER_OF_BYTES_LONG} * * @param bi the @{code BigInteger} to clip * @param numberOfBytes number of bytes to clip to * @return a new BigInteger */ public static BigInteger clip(BigInteger bi, int numberOfBytes) { byte [] unclipped = bi.toByteArray(); if (unclipped.length <= numberOfBytes) { //byte [] reversed = Arrays.copyOf(unclipped, numberOfBytes); //unclipped = ByteUtils.reverseArray(reversed); return bi; } byte [] constructionBytes = Arrays.copyOfRange(unclipped, unclipped.length -numberOfBytes , unclipped.length); return new BigInteger(constructionBytes); } // // /** // * Somewhat useless // * Discards less significant bytes // * @param bi the @{code BigInteger} to truncate // * @param numberOfBytes number of bytes to truncate to // * @return a new BigInteger // */ // public static BigInteger truncate(BigInteger bi, int numberOfBytes) { // byte [] unclipped = bi.toByteArray(); // if (unclipped.length <= numberOfBytes) { // return bi; // } // byte [] constructionBytes = Arrays.copyOfRange(unclipped, // 0 , numberOfBytes); // return new BigInteger(constructionBytes); // } // /** * Big endian * @param bi to document * @param numberOfBytes to document * @return to document */ public static byte [] clipToByteArray(BigInteger bi, int numberOfBytes) { BigInteger clipped = clip(bi,numberOfBytes); byte [] rtn = clipped.toByteArray(); if (rtn.length == numberOfBytes) { return rtn; } rtn = Arrays.copyOf(rtn, numberOfBytes); return ByteUtils.reverseArray(rtn); } /** * Little endian * @param bi to document * @param numberOfBytes to document * @return to document */ public static byte [] clipToByteArrayLittleEndian(BigInteger bi, int numberOfBytes) { BigInteger clipped = clip(bi,numberOfBytes); byte [] rtn = clipped.toByteArray(); if (rtn.length == numberOfBytes) { return ByteUtils.reverseArray(rtn); } rtn = Arrays.copyOf(rtn, numberOfBytes); return rtn; } }