All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.geolatte.geom.ByteBuffer Maven / Gradle / Ivy

Go to download

This geoLatte-geom library offers a geometry model that conforms to the OGC Simple Features for SQL specification.

The newest version!
/*
 * This file is part of the GeoLatte project.
 *
 *     GeoLatte 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.
 *
 *     GeoLatte 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 GeoLatte.  If not, see .
 *
 * Copyright (C) 2010 - 2011 and Ownership of code is shared by:
 * Qmino bvba - Romeinsestraat 18 - 3001 Heverlee  (http://www.qmino.com)
 * Geovise bvba - Generaal Eisenhowerlei 9 - 2140 Antwerpen (http://www.geovise.com)
 */

package org.geolatte.geom;

import java.nio.BufferOverflowException;
import java.nio.BufferUnderflowException;
import java.util.List;
import java.util.Objects;

/**
 * A byte buffer class.
 *
 * 

This class is modeled on the java.nio.Buffer interface. Specifically, the properties capacity and limit are * defined as for Buffer.

* *
    *
  • A buffer's capacity is the number of elements it contains. The capacity of a buffer is never negative and never changes.
  • *
  • A buffer's limit is the index of the first element that should not be read or written. A buffer's limit is never negative and is never greater than its capacity.
  • *
* * @author Karel Maesen, Geovise BVBA * creation-date: Oct 29, 2010 */ public class ByteBuffer { /** * byte size for unsigned int */ public static final int UINT_SIZE = 4; /** * byte size for doubles */ public static final int DOUBLE_SIZE = 8; /** * Max. permissible value for an unsigned int. */ public static final long UINT_MAX_VALUE = 4294967295L; private final java.nio.ByteBuffer buffer; private ByteBuffer(java.nio.ByteBuffer buffer) { this.buffer = buffer; } /** * Creates a ByteBuffer from a hexadecimal string. * *

Every two chars in the string are interpreted as the hexadecimal representation of a byte. * If the string length is odd, the last character will be ignored.

* * @param hexString the bytes represented in hexadecimal form * @return A ByteBuffer based on the hexadecimal string */ public static ByteBuffer from(String hexString) { if (hexString == null) throw new IllegalArgumentException("Cannot create ByteBuffer from null input String."); int size = hexString.length() / 2; // this will drop the last char, if hexString is not even. java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(size); for (int i = 0; i < size * 2; i += 2) { final char firstLetterOrNumber = hexString.charAt(i); final char secondLetterOrNumber = hexString.charAt(i + 1); final byte firstDigit; final byte secondDigit; if (firstLetterOrNumber == '+') { firstDigit = 0; secondDigit = charToHex(secondLetterOrNumber); } else if (firstLetterOrNumber == '-'){ firstDigit = 0; secondDigit = (byte)-charToHex(secondLetterOrNumber); }else { firstDigit = charToHex(firstLetterOrNumber); secondDigit = charToHex(secondLetterOrNumber); } final byte b = (byte)((firstDigit << 4) | secondDigit); buffer.put(b); } buffer.rewind(); return new ByteBuffer(buffer); } /** * Returns this instance as a hexadecimal string. * * @return A string representation of this ByteBuffer in hexadecimal form */ public String toString() { StringBuilder builder = new StringBuilder(); int savedPosition = buffer.position(); rewind(); for (int i = 0; i < limit(); i++) { int hexValue = readByte(); appendHexByteRepresentation(builder, hexValue); } buffer.position(savedPosition); return builder.toString(); } private void appendHexByteRepresentation(StringBuilder builder, int hexValue) { String byteStr = Integer.toHexString(hexValue).toUpperCase(); if (byteStr.length() == 1) { builder.append("0").append(byteStr); } else { builder.append(byteStr); } } private int readByte() { int hexValue = get(); hexValue = (hexValue << 24) >>> 24; return hexValue; } /** * Wraps a byte array into a ByteBuffer. * * The new buffer will be backed by the given byte array; that is, modifications to the buffer will cause the array * to be modified and vice versa. The new buffer's capacity and limit will be bytes.length. * * @param bytes The array that will back this buffer * @return The new byte buffer. */ public static ByteBuffer from(byte[] bytes) { java.nio.ByteBuffer buffer = java.nio.ByteBuffer.wrap(bytes); return new ByteBuffer(buffer); } /** * Transforms a List of ByteBuffers to a single ByteBuffer */ public static ByteBuffer collect(List buffers) { if(buffers == null || buffers.isEmpty()) return allocate(0); int totalSize = 0; for( ByteBuffer b: buffers){ totalSize += b.capacity(); } byte[] bytes = new byte[totalSize]; int p = 0; for( ByteBuffer b: buffers){ java.lang.System.arraycopy(b.toByteArray(), 0, bytes, p, b.capacity()); p += b.capacity(); } return from(bytes); } /** * Allocates a new ByteBuffer of the specified capacity. * * The new buffer's position will be zero, its limit will be its capacity and each of its elements will be * initialized to zero. * * @param capacity The new buffer's capacity, in bytes * @return a new ByteBuffer instance of the specified capacity */ public static ByteBuffer allocate(int capacity) { return new ByteBuffer(java.nio.ByteBuffer.allocate(capacity)); } /** * Relative get method. Reads the byte at this buffer's current position, and then increments the position. * * @return The byte at the buffer's current position * @throws BufferAccessException If the buffer's current position is not smaller than its limit. */ public byte get() { try { return buffer.get(); } catch (BufferOverflowException e) { throw new BufferAccessException(e.getMessage()); } } /** * Writes the given byte into this buffer at the current position, and then increments the position. * * @param value The byte to be written * @throws BufferAccessException If this buffer's current position is not smaller than its limit. */ public void put(byte value) { try { buffer.put(value); } catch (BufferOverflowException e) { throw new BufferAccessException(e.getMessage()); } } /** * Returns this buffer's capacity. * * @return The capacity of this buffer */ public int capacity() { return buffer.capacity(); } /** * Returns this buffer's limit. * * @return The limit of this buffer */ public int limit() { return buffer.limit(); } /** * Rewinds the buffer. * *

After rewind, the next get() or put() will take place on the first element of this instance.

*/ public void rewind() { buffer.rewind(); } /** * Reports if this buffer is empty (holds no bytes). * * @return True if limit is 0, otherwise false */ public boolean isEmpty() { return buffer.limit() == 0; } /** * Sets the byte order for this instance. * * @param wbo The new byte order, either {@link ByteOrder#XDR XDR} or {@link ByteOrder#NDR NDR} */ public void setByteOrder(ByteOrder wbo) { buffer.order(wbo.getByteOrder()); } /** * Reads the next 4 bytes as an int from this instance at the current position, taking into account the byte-order, * and then increments the position by four. * * @return The int value at the buffer's current position * @throws BufferAccessException If there are fewer than four bytes remaining in this buffer. */ public int getInt() { try { return buffer.getInt(); } catch (BufferUnderflowException e) { throw new BufferAccessException(e.getMessage()); } } /** * Writes the specified int-value as 4 bytes to this instance at the current position, respecting the byte-order, * and then increments the position by four. * * @param value The int value to be written * @throws BufferAccessException If there are fewer than four bytes remaining in this buffer. */ public void putInt(int value) { try { buffer.putInt(value); } catch (BufferOverflowException e) { throw new BufferAccessException(e.getMessage()); } } /** * Reads the next 8 bytes as a long from this instance at the current position, taking into account the byte-order, * and then increments the position by eight. * * @return The long value at the buffer's current position * @throws BufferAccessException If there are fewer than eight bytes remaining in this buffer. */ public long getLong() { try { return buffer.getLong(); } catch (BufferUnderflowException e) { throw new BufferAccessException(e.getMessage()); } } /** * Writes the specified long value as 8 bytes to this instance at the current position, respecting the byte-order, * and then increments the position by eight. * * @param value The long value to be written * @throws BufferAccessException If there are fewer than eight bytes remaining in this buffer. */ public void putLong(long value) { try { buffer.putLong(value); } catch (BufferOverflowException e) { throw new BufferAccessException(e.getMessage()); } } /** * Reads the next 4 bytes as a float from this instance at the current position, taking into account the byte-order, * and then increments the position by four. * * @return The float value at the buffer's current position * @throws BufferAccessException If there are fewer than four bytes remaining in this buffer. */ public float getFloat() { try { return buffer.getFloat(); } catch (BufferUnderflowException e) { throw new BufferAccessException(e.getMessage()); } } /** * Writes the specified float-value as 4 bytes to this instance at the current position, respecting the byte-order, * and then increments the position by four. * * @param value The float value to be written * @throws BufferAccessException If there are fewer than four bytes remaining in this buffer. */ public void putFloat(float value) { try { buffer.putFloat(value); } catch (BufferOverflowException e) { throw new BufferAccessException(e.getMessage()); } } /** * Reads the next 8 bytes as a double from this instance at the current position, taking into account the byte-order, * and then increments the position by eight. * * @return The double value at the buffer's current position * @throws BufferAccessException If there are fewer than eight bytes remaining in this buffer. */ public double getDouble() { try { return buffer.getDouble(); } catch (BufferUnderflowException e) { throw new BufferAccessException(e.getMessage()); } } /** * Writes the specified double-value as 8 bytes to this instance at the current position, respecting the byte-order, * and then increments the position by eight. * * @param value The double value to be written * @throws BufferAccessException If there are fewer than eight bytes remaining in this buffer. */ public void putDouble(Double value) { try { buffer.putDouble(value); } catch (BufferOverflowException e) { throw new BufferAccessException(e.getMessage()); } } /** * Reads the next 4 bytes as an unsigned integer from this instance at the current position, * taking into account the byte-order, and then increments the position by four. * * @return The value of the 4-byte unsigned integer at the current position as a long * @throws BufferAccessException If there are fewer than four bytes remaining in this buffer */ public long getUInt() { try { int signedInt = buffer.getInt(); return signedInt & 0xffffffffL; //cast the signed int to an unsigned value in the bottom 32 bits of a long } catch (BufferUnderflowException e) { throw new BufferAccessException(e.getMessage()); } } /** * Interprets the specified long-value as and unsigned integer, and appends it as 4 bytes * to this instance at the current position, respecting the byte-order. * * @param value The unsigned integer value to be written * @throws RuntimeException If the specified value is larger than the largest unsigned integer (4294967295L) * @throws BufferAccessException If there are fewer than eight bytes remaining in this buffer. */ public void putUInt(long value) { if (value > UINT_MAX_VALUE) throw new RuntimeException("Value received doesn't fit in unsigned integer"); try { buffer.putInt((int) value); } catch (BufferOverflowException e) { throw new BufferAccessException(e.getMessage()); } } /** * Gets the byte order of this instance. * * @return This buffer's byte order */ public ByteOrder getByteOrder() { java.nio.ByteOrder order = buffer.order(); return ByteOrder.valueOf(order); } /** * Returns the byte array that backs this buffer. * * @return The array that backs this buffer */ public byte[] toByteArray(){ return buffer.array(); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ByteBuffer that = (ByteBuffer) o; if (buffer != null ? !buffer.equals(that.buffer) : that.buffer != null) return false; return true; } @Override public int hashCode() { return buffer != null ? buffer.hashCode() : 0; } /** * Used for testing purposes. * * @param other another ByteBuffer * @return true if both buffers contain the same bytes, false otherwise */ public boolean hasSameContent(ByteBuffer other) { if (other == null) return false; if (this.limit() != other.limit()) return false; int thisSavedPosition = this.buffer.position(); int otherSavedPosition = other.buffer.position(); this.rewind(); other.rewind(); for (int i = 0; i < this.limit(); i++) { if (this.get() != other.get()) return false; } this.buffer.position(thisSavedPosition); other.buffer.position(otherSavedPosition); return true; } private static byte charToHex(int letterOrNumber) { final int number; if (letterOrNumber <= '9'){ number = letterOrNumber - '0'; if (number < 0) throw numberFormatException(letterOrNumber); return (byte) number; } else { // The letters 'A' - 'F' and 'a' - 'f' differ only at bit position 6. // If bit 6 is zero, then it is uppercase int letterCaseInsensitive = letterOrNumber & ~(1 << 5); if (letterCaseInsensitive <= 'F') { number = letterCaseInsensitive - 'A' + 10; if (number < 10) throw numberFormatException(letterOrNumber); return (byte) number; } } throw numberFormatException(letterOrNumber); } private static NumberFormatException numberFormatException(int letterOrNumber) { return new NumberFormatException((char)letterOrNumber + " is not a hex digit"); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy