package org.sputnikdev.bluetooth.gattparser.num; /*- * #%L * org.sputnikdev:bluetooth-gatt-parser * %% * Copyright (C) 2017 Sputnik Dev * %% * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * #L% */ import java.math.BigInteger; import java.util.BitSet; /** * Two's complement & little-endian number formatter. * Stateless and threadsafe. */ public class TwosComplementNumberFormatter implements RealNumberFormatter { private final static int BIG_INTEGER_MAX_SIZE = 20 * 8; @Override public Integer deserializeInteger(BitSet bits, int size, boolean signed) { if (size > 32) { throw new IllegalArgumentException("size must be less or equal 32"); } if (size == 1) { signed = false; } boolean isNegative = signed && size > 1 && bits.get(size - 1); int value = isNegative ? -1 : 0; for (int i = 0; i < bits.length() && i < size; i++) { if (isNegative && !bits.get(i)) { value ^= 1 << i; } else if (!isNegative && bits.get(i)) { value |= 1 << i; } } return value; } @Override public Long deserializeLong(BitSet bits, int size, boolean signed) { if (size > 64) { throw new IllegalArgumentException("size must be less or equal than 64"); } if (size == 1) { signed = false; } boolean isNegative = signed && size > 1 && bits.get(size - 1); long value = isNegative ? -1L : 0L; for (int i = 0; i < bits.length() && i < size; i++) { if (isNegative && !bits.get(i)) { value ^= 1L << i; } else if (!isNegative && bits.get(i)) { value |= 1L << i; } } return value; } @Override public BigInteger deserializeBigInteger(BitSet bits, int size, boolean signed) { if (size == 1) { signed = false; } boolean isNegative = signed && size > 1 && bits.get(size - 1); BigInteger value = isNegative ? BigInteger.ONE.negate() : BigInteger.ZERO; for (int i = 0; i < bits.length() && i < size; i++) { if (isNegative && !bits.get(i)) { value = value.clearBit(i); } else if (!isNegative && bits.get(i)) { value = value.setBit(i); } } return value; } @Override public BitSet serialize(Integer number, int size, boolean signed) { if (size == 1) { signed = false; } int length = Math.min(size, Integer.SIZE); BitSet bitSet = BitSet.valueOf(new long[] { number }).get(0, length); if (signed && number < 0) { bitSet.set(length - 1); } return bitSet; } @Override public BitSet serialize(Long number, int size, boolean signed) { if (size == 1) { signed = false; } int length = Math.min(size, Long.SIZE); BitSet bitSet = BitSet.valueOf(new long[] { number }).get(0, length); if (signed && number < 0) { bitSet.set(length - 1); } return bitSet; } @Override public BitSet serialize(BigInteger number, int size, boolean signed) { if (size == 1) { signed = false; } BitSet bitSet = new BitSet(size); int length = Math.min(size, BIG_INTEGER_MAX_SIZE); for (int i = 0; i < length - (signed ? 1 : 0); i++) { if (number.testBit(i)) { bitSet.set(i); } } if (signed && number.signum() == -1) { bitSet.set(length - 1); } return bitSet; } }