blob: 296cf22c5fa12bbfa57c6ab73d4bfed4f7940ee3 [file] [log] [blame]
// 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() {}
}