package org.jcodec.containers.mkv.util;
import java.lang.StringBuilder;
/**
* This class is part of JCodec ( www.jcodec.org ) This software is distributed under FreeBSD License
*
* EBML IO implementation
*
* @author The JCodec project
*
*/
public class EbmlUtil {
/**
* Encodes unsigned integer with given length
*
* @param value
* unsigned integer to be encoded
* @param length
* ebml sequence length
* @return
*/
public static byte[] ebmlEncodeLen(long value, int length) {
byte[] b = new byte[length];
for (int idx = 0; idx < length; idx++) {
// Rightmost bytes should go to end of array to preserve big-endian notation
b[length - idx - 1] = (byte) ((value >>> (8 * idx)) & 0xFFL);
}
b[0] |= 0x80 >>> (length - 1);
return b;
}
/**
* Encodes unsigned integer value according to ebml convention
*
* @param value
* unsigned integer to be encoded
* @return
*/
public static byte[] ebmlEncode(long value) {
return ebmlEncodeLen(value, ebmlLength(value));
}
public static final byte[] lengthOptions = { 0, (byte) 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
/**
* This method is used mostly during reading EBML bitstream. It asnwers the question "What is the length of an integer (signed/unsigned) encountered in the bitstream"
*
* @param b
* @return
*/
static public int computeLength(byte b) {
if (b == 0x00)
throw new RuntimeException("Invalid head element for ebml sequence");
int i = 1;
while ((b & lengthOptions[i]) == 0)
i++;
return i;
}
public static final long one = 0x7F;
// 0x3F 0x80
public static final long two = 0x3F80;
// 0x1F 0xC0 0x00
public static final long three = 0x1FC000;
// 0x0F 0xE0 0x00 0x00
public static final long four = 0x0FE00000;
// 0x07 0xF0 0x00 0x00 0x00
public static final long five = 0x07F0000000L;
// 0x03 0xF8 0x00 0x00 0x00 0x00
public static final long six = 0x03F800000000L;
// 0x01 0xFC 0x00 0x00 0x00 0x00 0x00
public static final long seven = 0x01FC0000000000L;
// 0x00 0xFE 0x00 0x00 0x00 0x00 0x00 0x00
public static final long eight = 0xFE000000000000L;
public static final long[] ebmlLengthMasks = new long[] { 0, one, two, three, four, five, six, seven, eight };
/**
* This method is used mostly during writing EBML bitstream. It answers the following question "How many bytes should be used to encode unsigned integer value"
*
* @param v
* unsigned integer to be encoded
* @return
*/
public static int ebmlLength(long v) {
if (v == 0)
return 1;
int length = 8;
while (length > 0 && (v & ebmlLengthMasks[length]) == 0)
length--;
return length;
}
public static String toHexString(byte[] a) {
StringBuilder sb = new StringBuilder();
for (byte b : a)
sb.append(String.format("0x%02x ", b & 0xff));
return sb.toString();
}
}