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