| // Copyright 2008 Google Inc. All rights reserved. |
| // http://code.google.com/p/protobuf/ |
| // |
| // Redistribution and use in source and binary forms, with or without |
| // modification, are permitted provided that the following conditions are |
| // met: |
| // |
| // * Redistributions of source code must retain the above copyright |
| // notice, this list of conditions and the following disclaimer. |
| // * Redistributions in binary form must reproduce the above |
| // copyright notice, this list of conditions and the following disclaimer |
| // in the documentation and/or other materials provided with the |
| // distribution. |
| // * Neither the name of Google Inc. nor the names of its |
| // contributors may be used to endorse or promote products derived from |
| // this software without specific prior written permission. |
| // |
| // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| |
| package com.google.gerrit.server.ioutil; |
| |
| import static java.nio.charset.StandardCharsets.UTF_8; |
| |
| import com.google.gerrit.entities.CodedEnum; |
| import java.io.EOFException; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import org.eclipse.jgit.util.IO; |
| |
| public class BasicSerialization { |
| private static final byte[] NO_BYTES = {}; |
| |
| private static int safeRead(InputStream input) throws IOException { |
| final int b = input.read(); |
| if (b == -1) { |
| throw new EOFException(); |
| } |
| return b; |
| } |
| |
| /** Read a fixed-width 64 bit integer in network byte order (big-endian). */ |
| public static long readFixInt64(InputStream input) throws IOException { |
| final long h = readFixInt32(input); |
| final long l = readFixInt32(input) & 0xFFFFFFFFL; |
| return (h << 32) | l; |
| } |
| |
| /** Write a fixed-width 64 bit integer in network byte order (big-endian). */ |
| public static void writeFixInt64(OutputStream output, long val) throws IOException { |
| writeFixInt32(output, (int) (val >>> 32)); |
| writeFixInt32(output, (int) (val & 0xFFFFFFFFL)); |
| } |
| |
| /** Read a fixed-width 32 bit integer in network byte order (big-endian). */ |
| public static int readFixInt32(InputStream input) throws IOException { |
| final int b1 = safeRead(input); |
| final int b2 = safeRead(input); |
| final int b3 = safeRead(input); |
| final int b4 = safeRead(input); |
| return (b1 << 24) | (b2 << 16) | (b3 << 8) | b4; |
| } |
| |
| /** Write a fixed-width 32 bit integer in network byte order (big-endian). */ |
| public static void writeFixInt32(OutputStream output, int val) throws IOException { |
| output.write((val >>> 24) & 0xFF); |
| output.write((val >>> 16) & 0xFF); |
| output.write((val >>> 8) & 0xFF); |
| output.write(val & 0xFF); |
| } |
| |
| /** Read a varint from the input, one byte at a time. */ |
| public static int readVarInt32(InputStream input) throws IOException { |
| int result = 0; |
| int offset = 0; |
| for (; offset < 32; offset += 7) { |
| final int b = safeRead(input); |
| result |= (b & 0x7f) << offset; |
| if ((b & 0x80) == 0) { |
| return result; |
| } |
| } |
| throw new EOFException(); |
| } |
| |
| /** Write a varint; value is treated as an unsigned value. */ |
| public static void writeVarInt32(OutputStream output, int value) throws IOException { |
| while (true) { |
| if ((value & ~0x7F) == 0) { |
| output.write(value); |
| return; |
| } |
| output.write((value & 0x7F) | 0x80); |
| value >>>= 7; |
| } |
| } |
| |
| /** Read a fixed length byte array whose length is specified as a varint. */ |
| public static byte[] readBytes(InputStream input) throws IOException { |
| final int len = readVarInt32(input); |
| if (len == 0) { |
| return NO_BYTES; |
| } |
| final byte[] buf = new byte[len]; |
| IO.readFully(input, buf, 0, len); |
| return buf; |
| } |
| |
| /** Write a byte array prefixed by its length in a varint. */ |
| public static void writeBytes(OutputStream output, byte[] data) throws IOException { |
| writeBytes(output, data, 0, data.length); |
| } |
| |
| /** Write a byte array prefixed by its length in a varint. */ |
| public static void writeBytes(final OutputStream output, byte[] data, int offset, int len) |
| throws IOException { |
| writeVarInt32(output, len); |
| output.write(data, offset, len); |
| } |
| |
| /** Read a UTF-8 string, prefixed by its byte length in a varint. */ |
| public static String readString(InputStream input) throws IOException { |
| final byte[] bin = readBytes(input); |
| if (bin.length == 0) { |
| return null; |
| } |
| return new String(bin, 0, bin.length, UTF_8); |
| } |
| |
| /** Write a UTF-8 string, prefixed by its byte length in a varint. */ |
| public static void writeString(OutputStream output, String s) throws IOException { |
| if (s == null) { |
| writeVarInt32(output, 0); |
| } else { |
| writeBytes(output, s.getBytes(UTF_8)); |
| } |
| } |
| |
| /** Read an enum whose code is stored as a varint. */ |
| public static <T extends CodedEnum> T readEnum(InputStream input, T[] all) throws IOException { |
| final int val = readVarInt32(input); |
| for (T t : all) { |
| if (t.getCode() == val) { |
| return t; |
| } |
| } |
| throw new IOException("Invalid enum " + val + " for " + all[0].getClass()); |
| } |
| |
| /** Write an enum whose code is stored as a varint. */ |
| public static <T extends CodedEnum> void writeEnum(OutputStream output, T e) throws IOException { |
| writeVarInt32(output, e.getCode()); |
| } |
| |
| private BasicSerialization() {} |
| } |