|
| 1 | +package com.cosmian; |
| 2 | + |
| 3 | +import java.io.IOException; |
| 4 | +import java.io.InputStream; |
| 5 | +import java.io.OutputStream; |
| 6 | + |
| 7 | +public class Leb128 { |
| 8 | + |
| 9 | + final static Long MASK = 127L; |
| 10 | + |
| 11 | + final static Long HIGH_ORDER_BIT = 128L; |
| 12 | + |
| 13 | + /** |
| 14 | + * Write a u64 as an LEB128 |
| 15 | + * |
| 16 | + * @param os the {@link OutputStream} to write to |
| 17 | + * @param value the value to write |
| 18 | + * @throws IOException if the stream is in error |
| 19 | + */ |
| 20 | + public static void writeU64(OutputStream os, long value) throws IOException { |
| 21 | + |
| 22 | + while (value != 0) { |
| 23 | + |
| 24 | + long b = value & MASK; |
| 25 | + value = value >>> 7; |
| 26 | + if (value != 0) { |
| 27 | + b = b | HIGH_ORDER_BIT; |
| 28 | + } |
| 29 | + os.write((int) b & 0xFF); |
| 30 | + } |
| 31 | + } |
| 32 | + |
| 33 | + /** |
| 34 | + * Read an u64 encoded as an LEB 128 from a stream |
| 35 | + * |
| 36 | + * @param is the {@link InputStream} to read from |
| 37 | + * @return the long value |
| 38 | + * @throws IOException if the stream is in error |
| 39 | + */ |
| 40 | + public static long readU64(InputStream is) throws IOException { |
| 41 | + int shift = 0; |
| 42 | + long result = 0; |
| 43 | + |
| 44 | + boolean last; |
| 45 | + do { |
| 46 | + long b = is.read(); |
| 47 | + last = (b & HIGH_ORDER_BIT) != HIGH_ORDER_BIT; |
| 48 | + b = b & MASK; |
| 49 | + result |= (b << shift); |
| 50 | + shift += 7; |
| 51 | + } while (!last); |
| 52 | + return result; |
| 53 | + } |
| 54 | + |
| 55 | + /** |
| 56 | + * Read a byte array prepended with a LEB 128 u64 indicated its length Warning: the maximum array size is 2^31 |
| 57 | + * |
| 58 | + * @param is the {@link InputStream} to read the array from |
| 59 | + * @return the byte array |
| 60 | + * @throws IOException if the stream is in error or the number of bytes read is not the expected value |
| 61 | + */ |
| 62 | + public static byte[] readByteArray(InputStream is) throws IOException { |
| 63 | + long length = readU64(is); |
| 64 | + byte[] buffer = new byte[(int) length]; |
| 65 | + int actualLength = is.read(buffer); |
| 66 | + if (actualLength != length) { |
| 67 | + throw new IOException( |
| 68 | + "Error reading a byte array of " + length + " bytes: only " + actualLength + " bytes were read !"); |
| 69 | + } |
| 70 | + return buffer; |
| 71 | + } |
| 72 | + |
| 73 | + /** |
| 74 | + * Write a byte array prepended with a LEB128 u64 indicating its length |
| 75 | + * |
| 76 | + * @param os the {@link OutputStream} to write to |
| 77 | + * @param array the array to write |
| 78 | + * @throws IOException is the stream is in error |
| 79 | + */ |
| 80 | + public static void writeArray(OutputStream os, byte[] array) throws IOException { |
| 81 | + writeU64(os, (long) array.length); |
| 82 | + os.write(array); |
| 83 | + } |
| 84 | + |
| 85 | +} |
0 commit comments