/*
*
* Code derived and adapted from the Jitsi client side STUN framework.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.restcomm.media.stun.messages.attributes.general;
import java.util.ArrayList;
import java.util.Iterator;
import org.restcomm.media.stun.StunException;
import org.restcomm.media.stun.messages.attributes.StunAttribute;
public class UnknownAttributesAttribute extends StunAttribute {
public static String NAME = "UNKNOWN-ATTRIBUTES";
private ArrayList<Character> unknownAttributes;
public UnknownAttributesAttribute() {
super(StunAttribute.UNKNOWN_ATTRIBUTES);
this.unknownAttributes = new ArrayList<Character>();
}
/**
* Returns the length (in bytes) of this attribute's body.
*
* If the number of unknown attributes is an odd number, one of the
* attributes MUST be repeated in the list, so that the total length of the
* list is a multiple of 4 bytes.
*
* @return the length of this attribute's value (a multiple of 4).
*/
@Override
public char getDataLength() {
if (this.unknownAttributes == null) {
return 0;
}
char length = (char) unknownAttributes.size();
if ((length % 2) != 0) {
length++;
}
return (char) (length * 2);
}
/**
* Verifies whether the specified attributeID is contained by this
* attribute.
*
* @param attributeID
* the attribute id to look for.
* @return true if this attribute contains the specified attribute id.
*/
public boolean contains(char attributeID) {
return unknownAttributes.contains(new Character(attributeID));
}
public void addAttributeId(char attributeId) {
if (!contains(attributeId)) {
unknownAttributes.add(new Character(attributeId));
}
}
/**
* Returns an iterator over the list of attribute IDs contained by this
* attribute.
*
* @return an iterator over the list of attribute IDs contained by this
* attribute.
*/
public Iterator<Character> getAttributes() {
return unknownAttributes.iterator();
}
/**
* Returns the number of attribute IDs contained by this class.
*
* @return the number of attribute IDs contained by this class.
*/
public int getAttributeCount() {
return unknownAttributes.size();
}
/**
* Returns the attribute id with index i.
*
* @param index
* the index of the attribute id to return.
* @return the attribute id with index i.
*/
public char getAttribute(int index) {
return (unknownAttributes.get(index)).charValue();
}
@Override
public String getName() {
return NAME;
}
@Override
public boolean equals(Object other) {
if (other == null || !(other instanceof UnknownAttributesAttribute)) {
return false;
}
if (other == this) {
return true;
}
UnknownAttributesAttribute att = (UnknownAttributesAttribute) other;
if (att.getAttributeType() != this.getAttributeType()
|| att.getDataLength() != this.getDataLength()
|| !this.unknownAttributes.equals(att.unknownAttributes)) {
return false;
}
return true;
}
@Override
public byte[] encode() {
byte binValue[] = new byte[getDataLength() + HEADER_LENGTH];
int offset = 0;
// Type
binValue[offset++] = (byte) (getAttributeType() >> 8);
binValue[offset++] = (byte) (getAttributeType() & 0x00FF);
// Length
binValue[offset++] = (byte) (getDataLength() >> 8);
binValue[offset++] = (byte) (getDataLength() & 0x00FF);
Iterator<Character> attributes = getAttributes();
while (attributes.hasNext()) {
char att = attributes.next().charValue();
binValue[offset++] = (byte) (att >> 8);
binValue[offset++] = (byte) (att & 0x00FF);
}
// If the number of unknown attributes is an odd number, one of the
// attributes MUST be repeated in the list, so that the total length of
// the list is a multiple of 4 bytes.
if (offset < binValue.length) {
char att = getAttribute(0);
binValue[offset++] = (byte) (att >> 8);
binValue[offset++] = (byte) (att & 0x00FF);
}
return binValue;
}
@Override
protected void decodeAttributeBody(byte[] data, char offset, char length)
throws StunException {
if ((length % 2) != 0) {
throw new StunException("Attribute IDs are 2 bytes long and the "
+ "passed binary array has an odd length " + "value.");
}
char originalOffset = offset;
for (int i = offset; i < originalOffset + length; i += 2) {
char attributeID = (char) ((data[offset++] << 8) | (data[offset++]));
addAttributeId(attributeID);
}
}
}