/* * * * Copyright 2014 Orient Technologies LTD (info(at)orientechnologies.com) * * * * Licensed under the Apache License, Version 2.0 (the "License"); * * you may not use this file except in compliance with the License. * * You may obtain a copy of the License at * * * * http://www.apache.org/licenses/LICENSE-2.0 * * * * Unless required by applicable law or agreed to in writing, software * * distributed under the License is distributed on an "AS IS" BASIS, * * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * * See the License for the specific language governing permissions and * * limitations under the License. * * * * For more information: http://www.orientechnologies.com * */ package com.orientechnologies.orient.core.serialization; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; /** * Static helper class to transform any kind of basic data in bytes and vice versa. * * @author Luca Garulli */ public class OBinaryProtocol { public static final int SIZE_BYTE = 1; public static final int SIZE_CHAR = 2; public static final int SIZE_SHORT = 2; public static final int SIZE_INT = 4; public static final int SIZE_LONG = 8; public static byte[] char2bytes(final char value, final byte[] b, final int iBeginOffset) { b[iBeginOffset] = (byte) ((value >>> 8) & 0xFF); b[iBeginOffset + 1] = (byte) ((value >>> 0) & 0xFF); return b; } public static int long2bytes(final long value, final OutputStream iStream) throws IOException { final int beginOffset = iStream instanceof OMemoryStream ? ((OMemoryStream) iStream).getPosition() : -1; iStream.write((int) (value >>> 56) & 0xFF); iStream.write((int) (value >>> 48) & 0xFF); iStream.write((int) (value >>> 40) & 0xFF); iStream.write((int) (value >>> 32) & 0xFF); iStream.write((int) (value >>> 24) & 0xFF); iStream.write((int) (value >>> 16) & 0xFF); iStream.write((int) (value >>> 8) & 0xFF); iStream.write((int) (value >>> 0) & 0xFF); return beginOffset; } public static byte[] long2bytes(final long value) { return OBinaryProtocol.long2bytes(value, new byte[8], 0); } public static byte[] long2bytes(final long value, final byte[] b, final int iBeginOffset) { b[iBeginOffset] = (byte) ((value >>> 56) & 0xFF); b[iBeginOffset + 1] = (byte) ((value >>> 48) & 0xFF); b[iBeginOffset + 2] = (byte) ((value >>> 40) & 0xFF); b[iBeginOffset + 3] = (byte) ((value >>> 32) & 0xFF); b[iBeginOffset + 4] = (byte) ((value >>> 24) & 0xFF); b[iBeginOffset + 5] = (byte) ((value >>> 16) & 0xFF); b[iBeginOffset + 6] = (byte) ((value >>> 8) & 0xFF); b[iBeginOffset + 7] = (byte) ((value >>> 0) & 0xFF); return b; } public static int int2bytes(final int value, final OutputStream iStream) throws IOException { final int beginOffset = iStream instanceof OMemoryStream ? ((OMemoryStream) iStream).getPosition() : -1; iStream.write((value >>> 24) & 0xFF); iStream.write((value >>> 16) & 0xFF); iStream.write((value >>> 8) & 0xFF); iStream.write((value >>> 0) & 0xFF); return beginOffset; } public static byte[] int2bytes(final int value) { return OBinaryProtocol.int2bytes(value, new byte[4], 0); } public static byte[] int2bytes(final int value, final byte[] b, final int iBeginOffset) { b[iBeginOffset] = (byte) ((value >>> 24) & 0xFF); b[iBeginOffset + 1] = (byte) ((value >>> 16) & 0xFF); b[iBeginOffset + 2] = (byte) ((value >>> 8) & 0xFF); b[iBeginOffset + 3] = (byte) ((value >>> 0) & 0xFF); return b; } public static int short2bytes(final short value, final OutputStream iStream) throws IOException { final int beginOffset = iStream instanceof OMemoryStream ? ((OMemoryStream) iStream).getPosition() : -1; iStream.write((value >>> 8) & 0xFF); iStream.write((value >>> 0) & 0xFF); return beginOffset; } public static byte[] short2bytes(final short value) { return OBinaryProtocol.short2bytes(value, new byte[2], 0); } public static byte[] short2bytes(final short value, final byte[] b, final int iBeginOffset) { b[iBeginOffset] = (byte) ((value >>> 8) & 0xFF); b[iBeginOffset + 1] = (byte) ((value >>> 0) & 0xFF); return b; } public static long bytes2long(final byte[] b) { return OBinaryProtocol.bytes2long(b, 0); } public static long bytes2long(final InputStream iStream) throws IOException { return ((long) (0xff & iStream.read()) << 56 | (long) (0xff & iStream.read()) << 48 | (long) (0xff & iStream.read()) << 40 | (long) (0xff & iStream.read()) << 32 | (long) (0xff & iStream.read()) << 24 | (0xff & iStream.read()) << 16 | (0xff & iStream.read()) << 8 | (0xff & iStream.read())); } public static long bytes2long(final byte[] b, final int offset) { return ((0xff & b[offset + 7]) | (0xff & b[offset + 6]) << 8 | (0xff & b[offset + 5]) << 16 | (long) (0xff & b[offset + 4]) << 24 | (long) (0xff & b[offset + 3]) << 32 | (long) (0xff & b[offset + 2]) << 40 | (long) (0xff & b[offset + 1]) << 48 | (long) (0xff & b[offset]) << 56); } /** * Convert the byte array to an int. * * @param b The byte array * @return The integer */ public static int bytes2int(final byte[] b) { return bytes2int(b, 0); } public static int bytes2int(final InputStream iStream) throws IOException { return ((0xff & iStream.read()) << 24 | (0xff & iStream.read()) << 16 | (0xff & iStream.read()) << 8 | (0xff & iStream.read())); } /** * Convert the byte array to an int starting from the given offset. * * @param b The byte array * @param offset The array offset * @return The integer */ public static int bytes2int(final byte[] b, final int offset) { return (b[offset]) << 24 | (0xff & b[offset + 1]) << 16 | (0xff & b[offset + 2]) << 8 | ((0xff & b[offset + 3])); } public static int bytes2short(final InputStream iStream) throws IOException { return (short) ((iStream.read() << 8) | (iStream.read() & 0xff)); } public static short bytes2short(final byte[] b, final int offset) { return (short) ((b[offset] << 8) | (b[offset + 1] & 0xff)); } public static char bytes2char(final byte[] b, final int offset) { return (char) ((b[offset] << 8) + (b[offset + 1] & 0xff)); } public static String bytes2string(final byte[] iInput) { if (iInput == null) return null; return OBinaryProtocol.bytes2string(iInput, 0, iInput.length); } public static String bytes2string(final byte[] input, final int iBeginOffset, final int iLenght) { final char[] output = new char[iLenght]; // index input[] int i = iBeginOffset; // index output[] int j = 0; while (i < iLenght + iBeginOffset) { // get next byte unsigned int b = input[i++] & 0xff; // classify based on the high order 3 bits switch (b >>> 5) { default: // one byte encoding // 0xxxxxxx // use just low order 7 bits // 00000000 0xxxxxxx output[j++] = (char) (b & 0x7f); break; case 6: // two byte encoding // 110yyyyy 10xxxxxx // use low order 6 bits int y = b & 0x1f; // use low order 6 bits of the next byte // It should have high order bits 10, which we don't check. int x = input[i++] & 0x3f; // 00000yyy yyxxxxxx output[j++] = (char) (y << 6 | x); break; case 7: // three byte encoding // 1110zzzz 10yyyyyy 10xxxxxx assert (b & 0x10) == 0 : "UTF8Decoder does not handle 32-bit characters"; // use low order 4 bits final int z = b & 0x0f; // use low order 6 bits of the next byte // It should have high order bits 10, which we don't check. y = input[i++] & 0x3f; // use low order 6 bits of the next byte // It should have high order bits 10, which we don't check. x = input[i++] & 0x3f; // zzzzyyyy yyxxxxxx final int asint = (z << 12 | y << 6 | x); output[j++] = (char) asint; break; }// end switch }// end while return new String(output, 0/* offset */, j/* count */); } public static final byte[] string2bytes(final String iInputText) { if (iInputText == null) return null; final int len = iInputText.length(); // worst case, all chars could require 3-byte encodings. final byte[] output = new byte[len * 3]; // index output[] int j = 0; for (int i = 0; i < len; i++) { int c = iInputText.charAt(i); if (c < 0x80) { // 7-bits done in one byte. output[j++] = (byte) c; } else if (c < 0x800) { // 8-11 bits done in 2 bytes output[j++] = (byte) (0xC0 | c >> 6); output[j++] = (byte) (0x80 | c & 0x3F); } else { // 12-16 bits done in 3 bytes output[j++] = (byte) (0xE0 | c >> 12); output[j++] = (byte) (0x80 | c >> 6 & 0x3F); output[j++] = (byte) (0x80 | c & 0x3F); } }// end for // Prune back our byte array. For efficiency we could hand item back // partly filled, which is only a minor inconvenience to the caller // most of the time to save copying the array. final byte[] chopped = new byte[j]; System.arraycopy(output, 0, chopped, 0, j/* length */); return chopped; }// end encode }