| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| |
| package org.apache.giraph.utils; |
| |
| import com.esotericsoftware.kryo.io.Input; |
| |
| import java.io.IOException; |
| import java.io.UTFDataFormatException; |
| |
| /** |
| * Byte array input stream that uses Unsafe methods to deserialize |
| * much faster |
| */ |
| @edu.umd.cs.findbugs.annotations.SuppressWarnings( |
| "RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT") |
| public abstract class UnsafeReads extends Input implements ExtendedDataInput { |
| |
| /** |
| * Constructor |
| * |
| * @param length buf length |
| */ |
| public UnsafeReads(int length) { |
| limit = length; |
| } |
| |
| /** |
| * Constructor with offset |
| * |
| * @param offset offset in memory |
| * @param length buf length |
| */ |
| public UnsafeReads(long offset, int length) { |
| position = (int) offset; |
| limit = length; |
| } |
| |
| /** |
| * How many bytes are still available? |
| * |
| * @return Number of bytes available |
| */ |
| public abstract int available(); |
| |
| /** |
| * What position in the stream? |
| * |
| * @return Position |
| */ |
| public abstract int getPos(); |
| |
| /** |
| * Check whether there are enough remaining bytes for an operation |
| * |
| * @param requiredBytes Bytes required to read |
| */ |
| @Override |
| protected int require(int requiredBytes) { |
| if (available() < requiredBytes) { |
| throw new IndexOutOfBoundsException("require: Only " + |
| available() + " bytes remaining, trying to read " + requiredBytes); |
| } |
| return available(); |
| } |
| |
| @Override |
| public int skipBytes(int n) { |
| require(n); |
| position += n; |
| return n; |
| } |
| |
| @Override |
| public String readLine() throws IOException { |
| // Note that this code is mostly copied from DataInputStream |
| char[] tmpBuf = new char[128]; |
| |
| int room = tmpBuf.length; |
| int offset = 0; |
| int c; |
| |
| loop: |
| while (true) { |
| c = readByte(); |
| switch (c) { |
| case -1: |
| case '\n': |
| break loop; |
| case '\r': |
| int c2 = readByte(); |
| if ((c2 != '\n') && (c2 != -1)) { |
| position -= 1; |
| } |
| break loop; |
| default: |
| if (--room < 0) { |
| char[] replacebuf = new char[offset + 128]; |
| room = replacebuf.length - offset - 1; |
| System.arraycopy(tmpBuf, 0, replacebuf, 0, offset); |
| tmpBuf = replacebuf; |
| } |
| tmpBuf[offset++] = (char) c; |
| break; |
| } |
| } |
| if ((c == -1) && (offset == 0)) { |
| return null; |
| } |
| return String.copyValueOf(tmpBuf, 0, offset); |
| } |
| |
| @Override |
| public String readUTF() throws IOException { |
| // Note that this code is mostly copied from DataInputStream |
| int utflen = readUnsignedShort(); |
| |
| byte[] bytearr = new byte[utflen]; |
| char[] chararr = new char[utflen]; |
| |
| int c; |
| int char2; |
| int char3; |
| int count = 0; |
| int chararrCount = 0; |
| |
| readFully(bytearr, 0, utflen); |
| |
| while (count < utflen) { |
| c = (int) bytearr[count] & 0xff; |
| if (c > 127) { |
| break; |
| } |
| count++; |
| chararr[chararrCount++] = (char) c; |
| } |
| |
| while (count < utflen) { |
| c = (int) bytearr[count] & 0xff; |
| switch (c >> 4) { |
| case 0: |
| case 1: |
| case 2: |
| case 3: |
| case 4: |
| case 5: |
| case 6: |
| case 7: |
| /* 0xxxxxxx */ |
| count++; |
| chararr[chararrCount++] = (char) c; |
| break; |
| case 12: |
| case 13: |
| /* 110x xxxx 10xx xxxx*/ |
| count += 2; |
| if (count > utflen) { |
| throw new UTFDataFormatException( |
| "malformed input: partial character at end"); |
| } |
| char2 = (int) bytearr[count - 1]; |
| if ((char2 & 0xC0) != 0x80) { |
| throw new UTFDataFormatException( |
| "malformed input around byte " + count); |
| } |
| chararr[chararrCount++] = (char) (((c & 0x1F) << 6) | |
| (char2 & 0x3F)); |
| break; |
| case 14: |
| /* 1110 xxxx 10xx xxxx 10xx xxxx */ |
| count += 3; |
| if (count > utflen) { |
| throw new UTFDataFormatException( |
| "malformed input: partial character at end"); |
| } |
| char2 = (int) bytearr[count - 2]; |
| char3 = (int) bytearr[count - 1]; |
| if (((char2 & 0xC0) != 0x80) || ((char3 & 0xC0) != 0x80)) { |
| throw new UTFDataFormatException( |
| "malformed input around byte " + (count - 1)); |
| } |
| chararr[chararrCount++] = (char) (((c & 0x0F) << 12) | |
| ((char2 & 0x3F) << 6) | ((char3 & 0x3F) << 0)); |
| break; |
| default: |
| /* 10xx xxxx, 1111 xxxx */ |
| throw new UTFDataFormatException( |
| "malformed input around byte " + count); |
| } |
| } |
| // The number of chars produced may be less than utflen |
| return new String(chararr, 0, chararrCount); |
| } |
| } |