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

net.named_data.jndn.encoding.tlv.TlvEncoder Maven / Gradle / Ivy

Go to download

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.

There is a newer version: 0.25
Show newest version
/**
 * Copyright (C) 2014-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.encoding.tlv;

import java.nio.ByteBuffer;
import net.named_data.jndn.util.DynamicByteBuffer;

/**
 * A TlvEncoder holds an output buffer and has methods to output NDN-TLV.
 */
public class TlvEncoder {
  /**
   * Create a new TlvEncoder to use a DynamicByteBuffer with the initialCapacity.
   * When done, you should call getOutput().
   * @param initialCapacity The initial capacity of buffer().
   */
  public
  TlvEncoder(int initialCapacity)
  {
    output_ = new DynamicByteBuffer(initialCapacity);
    // We will start encoding from the back.
    output_.position(output_.limit());
  }

  /**
   * Create a new TlvEncoder with a default DynamicByteBuffer.
   * When done, you should call getOutput().
   */
  public
  TlvEncoder()
  {
    output_ = new DynamicByteBuffer(16);
    // We will start encoding from the back.
    output_.position(output_.limit());
  }

  /**
   * Get the number of bytes that have been written to the output.  You can
   * save this number, write sub TLVs, then subtract the new length from this
   * to get the total length of the sub TLVs.
   * @return The number of bytes that have been written to the output.
   */
  public final int
  getLength()
  {
    return output_.remaining();
  }

  /**
   * Encode varNumber as a VAR-NUMBER in NDN-TLV and write it to the output just
   * before getLength() from the back.  Advance getLength().
   * @param varNumber The non-negative number to encode. This is a Java 32-bit
   * int, so this does not support encoding a 64-bit VAR-NUMBER.
   */
  public final void
  writeVarNumber(int varNumber)
  {
    if (varNumber < 253) {
      int position = output_.setRemainingFromBack(output_.remaining() + 1);
      output_.buffer().put(position, (byte)(varNumber & 0xff));
    }
    else if (varNumber <= 0xffff) {
      int position = output_.setRemainingFromBack(output_.remaining() + 3);
      output_.buffer().put(position, (byte)253);
      output_.buffer().put(position + 1, (byte)((varNumber >> 8) & 0xff));
      output_.buffer().put(position + 2, (byte)(varNumber & 0xff));
    }
    else {
      // A Java int is 32 bits so ignore a 64-bit VAR-NUMBER.
      int position = output_.setRemainingFromBack(output_.remaining() + 5);
      output_.buffer().put(position, (byte)254);
      output_.buffer().put(position + 1, (byte)((varNumber >> 24) & 0xff));
      output_.buffer().put(position + 2, (byte)((varNumber >> 16) & 0xff));
      output_.buffer().put(position + 3, (byte)((varNumber >> 8) & 0xff));
      output_.buffer().put(position + 4, (byte)(varNumber & 0xff));
    }
  }

  /**
   * Encode the type and length as VAR-NUMBER and write to the output just
   * before getLength() from the back.  Advance getLength().
   * @param type The type of the TLV. This is a Java 32-bit int, so this does
   * not support encoding a 64-bit type code.
   * @param length The non-negative length of the TLV. This is a Java 32-bit
   * int, so this does not support encoding a 64-bit length.
   */
  public final void
  writeTypeAndLength(int type, int length)
  {
    // Write backwards.
    writeVarNumber(length);
    writeVarNumber(type);
  }

  /**
   * Encode value as a non-negative integer and write it to the output just
   * before getLength() from  the back. Advance getLength(). This does not write
   * a type or length for the value.
   * @param value The non-negative integer to encode. This is a Java 64-bit
   * long, so encoding of 64-bit values is supported (actually 63-bit because
   * a Java long is signed).
   * @throws Error if the value is negative.
   */
  public final void
  writeNonNegativeInteger(long value)
  {
    if (value < 0)
      throw new Error("TLV integer value may not be negative");

    // Write backwards.
    if (value <= 0xffL) {
      int position = output_.setRemainingFromBack(output_.remaining() + 1);
      output_.buffer().put(position, (byte)(value & 0xff));
    }
    else if (value <= 0xffffL) {
      int position = output_.setRemainingFromBack(output_.remaining() + 2);
      output_.buffer().put(position,     (byte)((value >> 8) & 0xff));
      output_.buffer().put(position + 1, (byte)(value & 0xff));
    }
    else if (value <= 0xffffffffL) {
      int position = output_.setRemainingFromBack(output_.remaining() + 4);
      output_.buffer().put(position,     (byte)((value >> 24) & 0xff));
      output_.buffer().put(position + 1, (byte)((value >> 16) & 0xff));
      output_.buffer().put(position + 2, (byte)((value >> 8) & 0xff));
      output_.buffer().put(position + 3, (byte)(value & 0xff));
    }
    else {
      int position = output_.setRemainingFromBack(output_.remaining() + 8);
      output_.buffer().put(position,     (byte)((value >> 56) & 0xff));
      output_.buffer().put(position + 1, (byte)((value >> 48) & 0xff));
      output_.buffer().put(position + 2, (byte)((value >> 40) & 0xff));
      output_.buffer().put(position + 3, (byte)((value >> 32) & 0xff));
      output_.buffer().put(position + 4, (byte)((value >> 24) & 0xff));
      output_.buffer().put(position + 5, (byte)((value >> 16) & 0xff));
      output_.buffer().put(position + 6, (byte)((value >> 8) & 0xff));
      output_.buffer().put(position + 7, (byte)(value & 0xff));
    }
  }

  /**
   * Write the type, then the length of the encoded value then encode value as a
   * non-negative integer and write it to the output just before getLength()
   * from  the back. Advance getLength().
   * @param type The type of the TLV. This is a Java 32-bit int, so this does
   * not support encoding a 64-bit type code.
   * @param value The non-negative integer to encode. This is a Java 64-bit
   * long, so encoding of 64-bit values is supported (actually 63-bit because
   * a Java long is signed).
   * @throws Error if the value is negative.
   */
  public final void
  writeNonNegativeIntegerTlv(int type, long value)
  {
    // Write backwards.
    int saveNBytes = output_.remaining();
    writeNonNegativeInteger(value);
    writeTypeAndLength(type, output_.remaining() - saveNBytes);
  }

  /**
   * If value is negative or null then do nothing, otherwise call
   * writeNonNegativeIntegerTlv.
   * @param type The type of the TLV. This is a Java 32-bit int, so this does
   * not support encoding a 64-bit type code.
   * @param value If negative do nothing, otherwise the integer to encode. This
   * is a Java 64-bit long, so encoding of 64-bit values is supported (actually
   * 63-bit because a Java long is signed).
   */
  public final void
  writeOptionalNonNegativeIntegerTlv(int type, long value)
  {
    if (value >= 0)
      writeNonNegativeIntegerTlv(type, value);
  }

  /**
   * If value is negative or null then do nothing, otherwise call
   * writeNonNegativeIntegerTlv.
   * @param type The type of the TLV. This is a Java 32-bit int, so this does
   * not support encoding a 64-bit type code.
   * @param value If negative do nothing, otherwise use (long)Math.round(value).
   */
  public final void
  writeOptionalNonNegativeIntegerTlvFromDouble(int type, double value)
  {
    if (value >= 0.0)
      writeNonNegativeIntegerTlv(type, (long)Math.round(value));
  }

  /**
   * Write the buffer from its position() to limit() to the output just
   * before getLength() from the back. Advance getLength() of the output. This
   * does NOT change buffer.position(). Note that this does not encode a type
   * and length; for that see writeBlobTlv.
   * @param buffer The byte buffer with the bytes to write. If buffer is null,
   * then do nothing.
   */
  public final void
  writeBuffer(ByteBuffer buffer)
  {
    if (buffer == null)
      return;

    // Write backwards.
    int position = output_.setRemainingFromBack
      (output_.remaining() + buffer.remaining());
    int saveBufferValuePosition = buffer.position();
    output_.buffer().put(buffer);
    // Restore positions after put.
    output_.position(position);
    buffer.position(saveBufferValuePosition);
  }

  /**
   * Write the type, then the length of the buffer then the buffer value from
   * its position() to limit() to the output just before getLength() from the
   * back. Advance getLength() of the output. This does NOT change
   * value.position().
   * @param type The type of the TLV. This is a Java 32-bit int, so this does
   * not support encoding a 64-bit type code.
   * @param value The byte buffer with the bytes of the blob.  If value is null,
   * then just write the type and length 0.
   */
  public final void
  writeBlobTlv(int type, ByteBuffer value)
  {
    if (value == null) {
      writeTypeAndLength(type, 0);
      return;
    }

    // Write backwards.
    writeBuffer(value);
    writeTypeAndLength(type, value.remaining());
  }

  /**
   * If the byte buffer value is null or value.remaining() is zero then do
   * nothing, otherwise call writeBlobTlv.
   * @param type The type of the TLV. This is a Java 32-bit int, so this does
   * not support encoding a 64-bit type code.
   * @param value If null or value.remaining() is zero do nothing, otherwise
   * the buffer with the bytes of the blob.
   */
  public final void
  writeOptionalBlobTlv(int type, ByteBuffer value)
  {
    if (value != null && value.remaining() > 0)
      writeBlobTlv(type, value);
  }

  /**
   * Return a slice of the output buffer up to the current length of the output
   * encoding.
   * @return A ByteBuffer which shares the same underlying buffer with the
   * output buffer.
   */
  public final ByteBuffer
  getOutput()
  {
    // The output buffer position is already at the beginning of the encoding.
    return output_.buffer().slice();
  }

  private final DynamicByteBuffer output_;
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy