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}