// 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 com.google.gerrit.reviewdb.client.CodedEnum; import org.eclipse.jgit.util.IO; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; public class BasicSerialization { private static final byte[] NO_BYTES = {}; private static int safeRead(final 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(final 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(final OutputStream output, final 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(final 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(final OutputStream output, final 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(final 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(final OutputStream output, int value) throws IOException { while (true) { if ((value & ~0x7F) == 0) { output.write(value); return; } else { output.write((value & 0x7F) | 0x80); value >>>= 7; } } } /** Read a fixed length byte array whose length is specified as a varint. */ public static byte[] readBytes(final 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(final OutputStream output, final 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, final byte[] data, final int offset, final 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(final 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(final OutputStream output, final 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(final InputStream input, final 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(final OutputStream output, final T e) throws IOException { writeVarInt32(output, e.getCode()); } private BasicSerialization() { } }