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

org.red5.io.matroska.ParserUtils Maven / Gradle / Ivy

There is a newer version: 2.0.15
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License") + you may not use this file except in compliance with the
 * License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under
 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */
package org.red5.io.matroska;

import static org.red5.io.matroska.VINT.MASK_BYTE_1;
import static org.red5.io.matroska.VINT.MASK_BYTE_2;
import static org.red5.io.matroska.VINT.MASK_BYTE_3;
import static org.red5.io.matroska.VINT.MASK_BYTE_4;
import static org.red5.io.matroska.VINT.MASK_BYTE_8;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;

import org.red5.io.matroska.dtd.CompoundTag;
import org.red5.io.matroska.dtd.Tag;
import org.red5.io.matroska.dtd.TagFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ParserUtils {

    private static Logger log = LoggerFactory.getLogger(ParserUtils.class);

    public static final int BIT_IN_BYTE = 8;

    /**
     * method used to parse : int, uint and date
     *
     * @param inputStream
     *            - stream to get value
     * @param size
     *            - size of the value in bytes
     * @return - parsed value as long
     * @throws IOException
     *             - in case of IO error
     */
    public static long parseInteger(InputStream inputStream, final int size) throws IOException {
        log.debug("parseInteger inputStream: {} size: {}", inputStream, size);
        byte[] buffer = new byte[size];
        int numberOfReadsBytes = inputStream.read(buffer, 0, size);
        log.debug("numberOfReadsBytes: {}", numberOfReadsBytes);
        //assert numberOfReadsBytes == size;
        long value = buffer[0] & (long) 0xff;
        for (int i = 1; i < size; ++i) {
            value = (value << BIT_IN_BYTE) | ((long) buffer[i] & (long) 0xff);
        }
        return value;
    }

    /**
     * method used to parse string
     *
     * @param inputStream
     *            - stream to get value
     * @param size
     *            - size of the value in bytes
     * @return - parsed value as {@link String}
     * @throws IOException
     *             - in case of IO error
     */
    public static String parseString(InputStream inputStream, final int size) throws IOException {
        if (0 == size) {
            return "";
        }

        byte[] buffer = new byte[size];
        int numberOfReadsBytes = inputStream.read(buffer, 0, size);
        assert numberOfReadsBytes == size;

        return new String(buffer, "UTF-8");
    }

    /**
     * method used to parse float and double
     *
     * @param inputStream
     *            - stream to get value
     * @param size
     *            - size of the value in bytes
     * @return - parsed value as double
     * @throws IOException
     *             - in case of IO error
     */
    public static double parseFloat(InputStream inputStream, final int size) throws IOException {
        byte[] buffer = new byte[size];
        int numberOfReadsBytes = inputStream.read(buffer, 0, size);
        assert numberOfReadsBytes == size;

        ByteBuffer byteBuffer = ByteBuffer.wrap(buffer).order(ByteOrder.BIG_ENDIAN);
        if (8 == size) {
            return byteBuffer.getDouble();
        }

        return byteBuffer.getFloat();
    }

    /**
     * method used to parse subelements of {@link CompoundTag}
     *
     * @param inputStream
     *            - stream to get value
     * @param size
     *            - size of the value in bytes
     * @return - parsed tag
     * @throws IOException
     *             - in case of IO error
     * @throws ConverterException
     *             - in case of any conversion exception
     */
    public static ArrayList parseMasterElement(InputStream inputStream, final int size) throws IOException, ConverterException {
        byte bufferForSubElements[] = new byte[size];
        int readOfBytes = inputStream.read(bufferForSubElements, 0, size);
        assert readOfBytes == size;

        ArrayList subElements = new ArrayList();
        ByteArrayInputStream inputStreamForSubElements = new ByteArrayInputStream(bufferForSubElements);
        while (0 != inputStreamForSubElements.available()) {
            subElements.add(parseTag(inputStreamForSubElements));
        }

        return subElements;
    }

    /**
     * method to parse byte array
     *
     * @param inputStream
     *            - stream to get value
     * @param size
     *            - size of the value in bytes
     * @return - parsed value as array of bytes
     * @throws IOException
     *             - in case of IO error
     */
    public static byte[] parseBinary(InputStream inputStream, final int size) throws IOException {
        byte value[] = new byte[size];
        int i = value.length;
        while (i != 0) {
            i -= inputStream.read(value, value.length - i, i);
        }

        return value;
    }

    /**
     * method to parse {@link VINT}
     *
     * @param inputStream
     *            - stream to get value
     * @return - parsed value
     * @throws IOException
     *             - in case of IO error
     */
    public static VINT readVINT(InputStream inputStream) throws IOException {
        byte[] vint;
        int fb = inputStream.read();
        int read = 0;
        assert fb > 0;

        int len = (fb >> 4);
        long mask = MASK_BYTE_4;
        if (len >= 0b1000) {
            read = 0;
            mask = MASK_BYTE_1;
            vint = new byte[1];
        } else if (len >= 0b0100) {
            mask = MASK_BYTE_2;
            vint = new byte[2];
            read = inputStream.read(vint, 1, 1);
            assert read == 1;
        } else if (len >= 0b0010) {
            mask = MASK_BYTE_3;
            vint = new byte[3];
            read = inputStream.read(vint, 1, 2);
            assert read == 2;
        } else if (len >= 0b0001) {
            vint = new byte[4];
            read = inputStream.read(vint, 1, 3);
            assert read == 3;
        } else {
            mask = MASK_BYTE_8;
            vint = new byte[8];
            read = inputStream.read(vint, 1, 7);
            assert read == 7;
        }
        vint[0] = (byte) fb;
        long binaryV = 0;
        for (int i = 0; i < vint.length; ++i) {
            binaryV += (0x00FF & vint[i]);
            if (i != vint.length - 1) {
                binaryV <<= BIT_IN_BYTE;
            }
        }
        return new VINT(binaryV, (byte) (read + 1), mask & binaryV);
    }

    /**
     * parsing tag by matroska specification matroska spec
     *
     * tag = VINT id, VINT size, data
     *
     * @param inputStream
     *            - stream to get value
     * @return tag, without parsing tag data, because it delegate to an tag itself
     * @throws IOException
     *             - in case of IO error
     * @throws ConverterException
     *             - in case of any conversion exception
     */
    public static Tag parseTag(InputStream inputStream) throws IOException, ConverterException {
        VINT id = readVINT(inputStream);
        VINT size = readVINT(inputStream);

        return TagFactory.createTag(id, size, inputStream);
    }

    /**
     * method to encode long as byte array of given size
     *
     * @param val
     *            - value to encode
     * @param size
     *            - size
     * @return - byte array
     */
    public static byte[] getBytes(long val, long size) {
        byte[] res = new byte[(int) size];
        long bv = val;
        for (int i = (int) size - 1; i >= 0; --i) {
            res[i] = (byte) (bv & 0xFF);
            bv >>= BIT_IN_BYTE;
        }
        return res;
    }

    /**
     * method to skip given amount of bytes in stream
     *
     * @param size
     *            - size to skip
     * @param input
     *            - input stream to process
     * @throws IOException
     *             - in case of IO error
     */
    public static void skip(long size, InputStream input) throws IOException {
        while (size > 0) {
            size -= input.skip(size);
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy