View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  package org.apache.hadoop.hbase.io.util;
20  
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.io.OutputStream;
24  import java.nio.ByteBuffer;
25  
26  import org.apache.hadoop.hbase.classification.InterfaceAudience;
27  import org.apache.hadoop.hbase.util.Pair;
28  
29  import com.google.common.base.Preconditions;
30  
31  /*
32   * It seems like as soon as somebody sets himself to the task of creating VInt encoding, his mind
33   * blanks out for a split-second and he starts the work by wrapping it in the most convoluted
34   * interface he can come up with. Custom streams that allocate memory, DataOutput that is only used
35   * to write single bytes... We operate on simple streams. Thus, we are going to have a simple
36   * implementation copy-pasted from protobuf Coded*Stream.
37   */
38  @InterfaceAudience.Private
39  public class StreamUtils {
40  
41    public static void writeRawVInt32(OutputStream output, int value) throws IOException {
42      while (true) {
43        if ((value & ~0x7F) == 0) {
44          output.write(value);
45          return;
46        } else {
47          output.write((value & 0x7F) | 0x80);
48          value >>>= 7;
49        }
50      }
51    }
52  
53    public static int readRawVarint32(InputStream input) throws IOException {
54      byte tmp = (byte) input.read();
55      if (tmp >= 0) {
56        return tmp;
57      }
58      int result = tmp & 0x7f;
59      if ((tmp = (byte) input.read()) >= 0) {
60        result |= tmp << 7;
61      } else {
62        result |= (tmp & 0x7f) << 7;
63        if ((tmp = (byte) input.read()) >= 0) {
64          result |= tmp << 14;
65        } else {
66          result |= (tmp & 0x7f) << 14;
67          if ((tmp = (byte) input.read()) >= 0) {
68            result |= tmp << 21;
69          } else {
70            result |= (tmp & 0x7f) << 21;
71            result |= (tmp = (byte) input.read()) << 28;
72            if (tmp < 0) {
73              // Discard upper 32 bits.
74              for (int i = 0; i < 5; i++) {
75                if (input.read() >= 0) {
76                  return result;
77                }
78              }
79              throw new IOException("Malformed varint");
80            }
81          }
82        }
83      }
84      return result;
85    }
86  
87    public static int readRawVarint32(ByteBuffer input) throws IOException {
88      byte tmp = input.get();
89      if (tmp >= 0) {
90        return tmp;
91      }
92      int result = tmp & 0x7f;
93      if ((tmp = input.get()) >= 0) {
94        result |= tmp << 7;
95      } else {
96        result |= (tmp & 0x7f) << 7;
97        if ((tmp = input.get()) >= 0) {
98          result |= tmp << 14;
99        } else {
100         result |= (tmp & 0x7f) << 14;
101         if ((tmp = input.get()) >= 0) {
102           result |= tmp << 21;
103         } else {
104           result |= (tmp & 0x7f) << 21;
105           result |= (tmp = input.get()) << 28;
106           if (tmp < 0) {
107             // Discard upper 32 bits.
108             for (int i = 0; i < 5; i++) {
109               if (input.get() >= 0) {
110                 return result;
111               }
112             }
113             throw new IOException("Malformed varint");
114           }
115         }
116       }
117     }
118     return result;
119   }
120 
121   /**
122    * Reads a varInt value stored in an array.
123    *
124    * @param input
125    *          Input array where the varInt is available
126    * @param offset
127    *          Offset in the input array where varInt is available
128    * @return A pair of integers in which first value is the actual decoded varInt value and second
129    *         value as number of bytes taken by this varInt for it's storage in the input array.
130    * @throws IOException
131    */
132   public static Pair<Integer, Integer> readRawVarint32(byte[] input, int offset) throws IOException {
133     int newOffset = offset;
134     byte tmp = input[newOffset++];
135     if (tmp >= 0) {
136       return new Pair<Integer, Integer>((int) tmp, newOffset - offset);
137     }
138     int result = tmp & 0x7f;
139     tmp = input[newOffset++];
140     if (tmp >= 0) {
141       result |= tmp << 7;
142     } else {
143       result |= (tmp & 0x7f) << 7;
144       tmp = input[newOffset++];
145       if (tmp >= 0) {
146         result |= tmp << 14;
147       } else {
148         result |= (tmp & 0x7f) << 14;
149         tmp = input[newOffset++];
150         if (tmp >= 0) {
151           result |= tmp << 21;
152         } else {
153           result |= (tmp & 0x7f) << 21;
154           tmp = input[newOffset++];
155           result |= tmp << 28;
156           if (tmp < 0) {
157             // Discard upper 32 bits.
158             for (int i = 0; i < 5; i++) {
159               tmp = input[newOffset++];
160               if (tmp >= 0) {
161                 return new Pair<Integer, Integer>(result, newOffset - offset);
162               }
163             }
164             throw new IOException("Malformed varint");
165           }
166         }
167       }
168     }
169     return new Pair<Integer, Integer>(result, newOffset - offset);
170   }
171 
172   public static short toShort(byte hi, byte lo) {
173     short s = (short) (((hi & 0xFF) << 8) | (lo & 0xFF));
174     Preconditions.checkArgument(s >= 0);
175     return s;
176   }
177 
178   public static void writeShort(OutputStream out, short v) throws IOException {
179     Preconditions.checkArgument(v >= 0);
180     out.write((byte) (0xff & (v >> 8)));
181     out.write((byte) (0xff & v));
182   }
183 
184   public static void writeInt(OutputStream out, int v) throws IOException {
185     out.write((byte) (0xff & (v >> 24)));
186     out.write((byte) (0xff & (v >> 16)));
187     out.write((byte) (0xff & (v >> 8)));
188     out.write((byte) (0xff & v));
189   }
190 
191   public static void writeLong(OutputStream out, long v) throws IOException {
192     out.write((byte) (0xff & (v >> 56)));
193     out.write((byte) (0xff & (v >> 48)));
194     out.write((byte) (0xff & (v >> 40)));
195     out.write((byte) (0xff & (v >> 32)));
196     out.write((byte) (0xff & (v >> 24)));
197     out.write((byte) (0xff & (v >> 16)));
198     out.write((byte) (0xff & (v >> 8)));
199     out.write((byte) (0xff & v));
200   }
201 
202   public static long readLong(InputStream in) throws IOException {
203     long result = 0;
204     for (int shift = 56; shift >= 0; shift -= 8) {
205       long x = in.read();
206       if (x < 0) throw new IOException("EOF");
207       result |= (x << shift);
208     }
209     return result;
210   }
211 }