001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018package org.apache.hadoop.hbase.io.util; 019 020import java.io.IOException; 021import java.io.InputStream; 022import java.io.OutputStream; 023import java.nio.ByteBuffer; 024import org.apache.hadoop.hbase.nio.ByteBuff; 025import org.apache.hadoop.hbase.util.Pair; 026import org.apache.yetus.audience.InterfaceAudience; 027 028import org.apache.hbase.thirdparty.com.google.common.base.Preconditions; 029 030/* 031 * It seems like as soon as somebody sets himself to the task of creating VInt encoding, his mind 032 * blanks out for a split-second and he starts the work by wrapping it in the most convoluted 033 * interface he can come up with. Custom streams that allocate memory, DataOutput that is only used 034 * to write single bytes... We operate on simple streams. Thus, we are going to have a simple 035 * implementation copy-pasted from protobuf Coded*Stream. 036 */ 037@InterfaceAudience.Private 038public class StreamUtils { 039 040 public static void writeRawVInt32(OutputStream output, int value) throws IOException { 041 while (true) { 042 if ((value & ~0x7F) == 0) { 043 output.write(value); 044 return; 045 } else { 046 output.write((value & 0x7F) | 0x80); 047 value >>>= 7; 048 } 049 } 050 } 051 052 public static int readRawVarint32(InputStream input) throws IOException { 053 byte tmp = (byte) input.read(); 054 if (tmp >= 0) { 055 return tmp; 056 } 057 int result = tmp & 0x7f; 058 if ((tmp = (byte) input.read()) >= 0) { 059 result |= tmp << 7; 060 } else { 061 result |= (tmp & 0x7f) << 7; 062 if ((tmp = (byte) input.read()) >= 0) { 063 result |= tmp << 14; 064 } else { 065 result |= (tmp & 0x7f) << 14; 066 if ((tmp = (byte) input.read()) >= 0) { 067 result |= tmp << 21; 068 } else { 069 result |= (tmp & 0x7f) << 21; 070 result |= (tmp = (byte) input.read()) << 28; 071 if (tmp < 0) { 072 // Discard upper 32 bits. 073 for (int i = 0; i < 5; i++) { 074 if (input.read() >= 0) { 075 return result; 076 } 077 } 078 throw new IOException("Malformed varint"); 079 } 080 } 081 } 082 } 083 return result; 084 } 085 086 public static int readRawVarint32(ByteBuff input) throws IOException { 087 byte tmp = input.get(); 088 if (tmp >= 0) { 089 return tmp; 090 } 091 int result = tmp & 0x7f; 092 if ((tmp = input.get()) >= 0) { 093 result |= tmp << 7; 094 } else { 095 result |= (tmp & 0x7f) << 7; 096 if ((tmp = input.get()) >= 0) { 097 result |= tmp << 14; 098 } else { 099 result |= (tmp & 0x7f) << 14; 100 if ((tmp = input.get()) >= 0) { 101 result |= tmp << 21; 102 } else { 103 result |= (tmp & 0x7f) << 21; 104 result |= (tmp = input.get()) << 28; 105 if (tmp < 0) { 106 // Discard upper 32 bits. 107 for (int i = 0; i < 5; i++) { 108 if (input.get() >= 0) { 109 return result; 110 } 111 } 112 throw new IOException("Malformed varint"); 113 } 114 } 115 } 116 } 117 return result; 118 } 119 120 /** 121 * Reads a varInt value stored in an array. n * Input array where the varInt is available n * 122 * Offset in the input array where varInt is available 123 * @return A pair of integers in which first value is the actual decoded varInt value and second 124 * value as number of bytes taken by this varInt for it's storage in the input array. 125 * @throws IOException When varint is malformed and not able to be read correctly 126 */ 127 public static Pair<Integer, Integer> readRawVarint32(byte[] input, int offset) 128 throws IOException { 129 int newOffset = offset; 130 byte tmp = input[newOffset++]; 131 if (tmp >= 0) { 132 return new Pair<>((int) tmp, newOffset - offset); 133 } 134 int result = tmp & 0x7f; 135 tmp = input[newOffset++]; 136 if (tmp >= 0) { 137 result |= tmp << 7; 138 } else { 139 result |= (tmp & 0x7f) << 7; 140 tmp = input[newOffset++]; 141 if (tmp >= 0) { 142 result |= tmp << 14; 143 } else { 144 result |= (tmp & 0x7f) << 14; 145 tmp = input[newOffset++]; 146 if (tmp >= 0) { 147 result |= tmp << 21; 148 } else { 149 result |= (tmp & 0x7f) << 21; 150 tmp = input[newOffset++]; 151 result |= tmp << 28; 152 if (tmp < 0) { 153 // Discard upper 32 bits. 154 for (int i = 0; i < 5; i++) { 155 tmp = input[newOffset++]; 156 if (tmp >= 0) { 157 return new Pair<>(result, newOffset - offset); 158 } 159 } 160 throw new IOException("Malformed varint"); 161 } 162 } 163 } 164 } 165 return new Pair<>(result, newOffset - offset); 166 } 167 168 public static Pair<Integer, Integer> readRawVarint32(ByteBuffer input, int offset) 169 throws IOException { 170 int newOffset = offset; 171 byte tmp = input.get(newOffset++); 172 if (tmp >= 0) { 173 return new Pair<>((int) tmp, newOffset - offset); 174 } 175 int result = tmp & 0x7f; 176 tmp = input.get(newOffset++); 177 if (tmp >= 0) { 178 result |= tmp << 7; 179 } else { 180 result |= (tmp & 0x7f) << 7; 181 tmp = input.get(newOffset++); 182 if (tmp >= 0) { 183 result |= tmp << 14; 184 } else { 185 result |= (tmp & 0x7f) << 14; 186 tmp = input.get(newOffset++); 187 if (tmp >= 0) { 188 result |= tmp << 21; 189 } else { 190 result |= (tmp & 0x7f) << 21; 191 tmp = input.get(newOffset++); 192 result |= tmp << 28; 193 if (tmp < 0) { 194 // Discard upper 32 bits. 195 for (int i = 0; i < 5; i++) { 196 tmp = input.get(newOffset++); 197 if (tmp >= 0) { 198 return new Pair<>(result, newOffset - offset); 199 } 200 } 201 throw new IOException("Malformed varint"); 202 } 203 } 204 } 205 } 206 return new Pair<>(result, newOffset - offset); 207 } 208 209 public static short toShort(byte hi, byte lo) { 210 short s = (short) (((hi & 0xFF) << 8) | (lo & 0xFF)); 211 Preconditions.checkArgument(s >= 0); 212 return s; 213 } 214 215 public static void writeShort(OutputStream out, short v) throws IOException { 216 Preconditions.checkArgument(v >= 0); 217 out.write((byte) (0xff & (v >> 8))); 218 out.write((byte) (0xff & v)); 219 } 220 221 public static void writeInt(OutputStream out, int v) throws IOException { 222 out.write((byte) (0xff & (v >> 24))); 223 out.write((byte) (0xff & (v >> 16))); 224 out.write((byte) (0xff & (v >> 8))); 225 out.write((byte) (0xff & v)); 226 } 227 228 public static void writeLong(OutputStream out, long v) throws IOException { 229 out.write((byte) (0xff & (v >> 56))); 230 out.write((byte) (0xff & (v >> 48))); 231 out.write((byte) (0xff & (v >> 40))); 232 out.write((byte) (0xff & (v >> 32))); 233 out.write((byte) (0xff & (v >> 24))); 234 out.write((byte) (0xff & (v >> 16))); 235 out.write((byte) (0xff & (v >> 8))); 236 out.write((byte) (0xff & v)); 237 } 238 239 public static long readLong(InputStream in) throws IOException { 240 long result = 0; 241 for (int shift = 56; shift >= 0; shift -= 8) { 242 long x = in.read(); 243 if (x < 0) throw new IOException("EOF"); 244 result |= (x << shift); 245 } 246 return result; 247 } 248}