001// License: GPL. For details, see LICENSE file.
002package org.openstreetmap.josm.data.protobuf;
003
004import java.util.ArrayList;
005import java.util.List;
006
007/**
008 * Parse packed values (only numerical values)
009 *
010 * @author Taylor Smock
011 * @since 17862
012 */
013public class ProtobufPacked {
014    private final byte[] bytes;
015    private final Number[] numbers;
016    private int location;
017
018    /**
019     * Create a new ProtobufPacked object
020     *
021     * @param bytes The packed bytes
022     */
023    public ProtobufPacked(byte[] bytes) {
024        this.location = 0;
025        this.bytes = bytes;
026        List<Number> numbersT = new ArrayList<>();
027        while (this.location < bytes.length) {
028            numbersT.add(ProtobufParser.convertByteArray(this.nextVarInt(), ProtobufParser.VAR_INT_BYTE_SIZE));
029        }
030
031        this.numbers = new Number[numbersT.size()];
032        for (int i = 0; i < numbersT.size(); i++) {
033            this.numbers[i] = numbersT.get(i);
034        }
035    }
036
037    /**
038     * Get the parsed number array
039     *
040     * @return The number array
041     */
042    public Number[] getArray() {
043        return this.numbers;
044    }
045
046    private byte[] nextVarInt() {
047        List<Byte> byteList = new ArrayList<>();
048        while ((this.bytes[this.location] & ProtobufParser.MOST_SIGNIFICANT_BYTE)
049          == ProtobufParser.MOST_SIGNIFICANT_BYTE) {
050            // Get rid of the leading bit (shift left 1, then shift right 1 unsigned)
051            byteList.add((byte) (this.bytes[this.location++] ^ ProtobufParser.MOST_SIGNIFICANT_BYTE));
052        }
053        // The last byte doesn't drop the most significant bit
054        byteList.add(this.bytes[this.location++]);
055        byte[] byteArray = new byte[byteList.size()];
056        for (int i = 0; i < byteList.size(); i++) {
057            byteArray[i] = byteList.get(i);
058        }
059
060        return byteArray;
061    }
062}