
net.named_data.jndn.util.Blob Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jndn-android-with-async-io Show documentation
Show all versions of jndn-android-with-async-io Show documentation
jNDN is a new implementation of a Named Data Networking client library written in Java. It is wire format compatible with the new NDN-TLV encoding, with NDNx and PARC's CCNx.
/**
* Copyright (C) 2013-2017 Regents of the University of California.
* @author: Jeff Thompson
*
* 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 .
* A copy of the GNU Lesser General Public License is in the file COPYING.
*/
package net.named_data.jndn.util;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
/**
* A Blob holds a pointer to an immutable ByteBuffer. We use an immutable
* buffer so that it is OK to pass the object into methods because the new or
* old owner can’t change the bytes.
* Note that the pointer to the ByteBuffer can be null.
*/
public class Blob implements Comparable {
/**
* Create a new Blob with a null pointer.
*/
public
Blob()
{
buffer_ = null;
}
/**
* Create a new Blob and take another pointer to the given blob's buffer.
* @param blob The Blob from which we take another pointer to the same buffer.
*/
public
Blob(Blob blob)
{
if (blob != null)
buffer_ = blob.buffer_;
else
buffer_ = null;
}
/**
* Create a new Blob from an existing ByteBuffer. IMPORTANT: If copy is
* false, after calling this constructor, if you keep a pointer to the buffer
* then you must treat it as immutable and promise not to change it.
* @param buffer The existing ByteBuffer. It is important that the buffer
* position and limit are correct.
* @param copy If true, copy the contents into a new byte array. If false,
* just take a slice which uses the existing byte array in buffer.
*/
public
Blob(ByteBuffer buffer, boolean copy)
{
if (buffer != null) {
if (copy) {
buffer_ = ByteBuffer.allocate(buffer.remaining());
// Put updates buffer.position(), so save and restore it.
int savePosition = buffer.position();
buffer_.put(buffer);
buffer.position(savePosition);
buffer_.flip();
}
else
buffer_ = buffer.slice();
}
else
buffer_ = null;
}
/**
* Create a new Blob from the the byte array. IMPORTANT: If copy is false,
* after calling this constructor, if you keep a pointer to the buffer then
* you must treat it as immutable and promise not to change it.
* @param value The byte array. If copy is true, this makes a copy.
* @param copy If true, copy the contents into a new byte array. If false,
* just use ByteBuffer.wrap which uses the existing byte array.
*/
public
Blob(byte[] value, boolean copy)
{
if (copy) {
buffer_ = ByteBuffer.allocate(value.length);
buffer_.put(value);
buffer_.flip();
}
else
buffer_ = ByteBuffer.wrap(value);
}
/**
* Create a new Blob with a copy of the bytes in the array.
* @param value The byte array to copy.
*/
public
Blob(byte[] value)
{
buffer_ = ByteBuffer.allocate(value.length);
buffer_.put(value);
buffer_.flip();
}
/**
* Create a new Blob with a copy of the bytes in the array.
* @param value The array of integer to copy where each integer is in
* the range 0 to 255.
*/
public
Blob(int[] value)
{
buffer_ = ByteBuffer.allocate(value.length);
for (int i = 0; i < value.length; ++i)
buffer_.put((byte)value[i]);
buffer_.flip();
}
/**
* Create a new Blob from the UTF-8 encoding of the Unicode string.
* @param value The Unicode string which is encoded as UTF-8.
*/
public
Blob(String value)
{
byte[] utf8;
try {
utf8 = value.getBytes("UTF-8");
} catch (UnsupportedEncodingException ex) {
// We don't expect this to happen.
throw new Error("UTF-8 encoder not supported: " + ex.getMessage());
}
buffer_ = ByteBuffer.allocate(utf8.length);
buffer_.put(utf8);
buffer_.flip();
}
/**
* Get the read-only ByteBuffer.
* @return The read-only ByteBuffer using asReadOnlyBuffer(), or null if the
* pointer is null.
*/
public final ByteBuffer
buf()
{
if (buffer_ != null)
// We call asReadOnlyBuffer each time because it is still allowed to
// change the position and limit on a read-only buffer, and we don't
// want the caller to modify our buffer_.
return buffer_.asReadOnlyBuffer();
else
return null;
}
/**
* Get a byte array by calling ByteBuffer.array() if possible (because the
* ByteBuffer slice covers the entire backing array). Otherwise return byte
* array as a copy of the ByteBuffer. This is called immutableArray to remind
* you not to change the contents of the returned array. This method is
* necessary because the read-only ByteBuffer returned by buf() doesn't allow
* you to call array().
* @return A byte array which you should not modify, or null if the pointer
* is null.
*/
public final byte[]
getImmutableArray()
{
if (buffer_ != null) {
// We can't call array() on a read only ByteBuffer.
if (!buffer_.isReadOnly()) {
byte[] array = buffer_.array();
if (array.length == buffer_.remaining())
// Assume the buffer_ covers the entire backing array, so just return.
return array;
}
// We have to copy to a new byte array.
ByteBuffer tempBuffer = ByteBuffer.allocate(buffer_.remaining());
int savePosition = buffer_.position();
tempBuffer.put(buffer_);
buffer_.position(savePosition);
tempBuffer.flip();
return tempBuffer.array();
}
else
return null;
}
/**
* Get the size of the buffer.
* @return The length (remaining) of the ByteBuffer, or 0 if the pointer is
* null.
*/
public final int
size()
{
if (buffer_ != null)
return buffer_.remaining();
else
return 0;
}
/**
* Check if the buffer pointer is null.
* @return True if the buffer pointer is null, otherwise false.
*/
public final boolean
isNull()
{
return buffer_ == null;
}
/**
* Return a hex string of buf() from position to limit.
* @return A string of hex bytes, or "" if the buffer is null.
*/
public final String
toHex()
{
if (buffer_ == null)
return "";
else
return toHex(buffer_);
}
/**
* Write a hex string of the contents of buffer from position to limit to the
* output.
* @param buffer The buffer.
* @param output The StringBuffer to write to.
*/
public static void
toHex(ByteBuffer buffer, StringBuffer output)
{
for (int i = buffer.position(); i < buffer.limit(); ++i) {
String hex = Integer.toHexString((int)buffer.get(i) & 0xff);
if (hex.length() <= 1)
// Append the leading zero.
output.append("0");
output.append(hex);
}
}
/**
* Return a hex string of the contents of buffer from position to limit.
* @param buffer The buffer.
* @return A string of hex bytes.
*/
public static String
toHex(ByteBuffer buffer)
{
StringBuffer output = new StringBuffer(buffer.remaining() * 2);
toHex(buffer, output);
return output.toString();
}
public final boolean equals(Blob other)
{
if (buffer_ == null)
return other.buffer_ == null;
else if (other.isNull())
return false;
else
return buffer_.equals(other.buffer_);
}
public boolean equals(Object other)
{
if (!(other instanceof Blob))
return false;
return equals((Blob)other);
}
/**
* Compare this to the other Blob using byte-by-byte comparison from their
* position to their limit. If this and other are both isNull(), then this
* returns 0. If this isNull() and the other is not, return -1. If this is not
* isNull() and the other is, return 1. We compare explicitly because a Blob
* uses a ByteBuffer which compares based on signed byte, not unsigned byte.
* @param other The other Blob to compare with.
* @return 0 If they compare equal, -1 if self is less than other, or 1 if
* self is greater than other. If both are equal up to the shortest, then
* return -1 if self is shorter than other, or 1 of self is longer than other.
*/
public final int
compare(Blob other)
{
if (buffer_ == null && other.buffer_ == null)
return 0;
if (buffer_ == null && other.buffer_ != null)
return -1;
if (buffer_ != null && other.buffer_ == null)
return 1;
// Manually compare elements as unsigned.
int r = Math.min(buffer_.remaining(), other.buffer_.remaining());
for (int i = 0; i < r; ++i) {
// b & 0xff makes the byte unsigned and returns an int.
int xThis = buffer_.get(buffer_.position() + i) & 0xff;
int xOther = other.buffer_.get(other.buffer_.position() + i) & 0xff;
if (xThis < xOther)
return -1;
if (xThis > xOther)
return 1;
}
// They are equal up to the shorter.
if (buffer_.remaining() < other.buffer_.remaining())
return -1;
if (buffer_.remaining() > other.buffer_.remaining())
return 1;
return 0;
}
public final int
compareTo(Object o) { return this.compare((Blob)o); }
// Also include this version for portability.
public final int
CompareTo(Object o) { return this.compare((Blob)o); }
/**
* If the hash code is already computed then return it, otherwise compute and
* return the hash code.
* @return The hash code for the buffer, or 0 if the buffer is null.
*/
public int hashCode()
{
if (!haveHashCode_) {
if (buffer_ == null)
hashCode_ = 0;
else
hashCode_ = buffer_.hashCode();
haveHashCode_ = true;
}
return hashCode_;
}
/**
* Decode the byte array as UTF8 and return the Unicode string.
* @return A unicode string, or "" if the buffer is null.
*/
public String
toString()
{
if (buffer_ == null)
return "";
else {
try {
return new String(getImmutableArray(), "UTF-8");
} catch (UnsupportedEncodingException ex) {
// We don't expect this to happen.
throw new Error("UTF-8 decoder not supported: " + ex.getMessage());
}
}
}
private final ByteBuffer buffer_;
private boolean haveHashCode_ = false;
private int hashCode_;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy