1 | /* |
2 | * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, |
3 | * and the EPL 1.0 (http://h2database.com/html/license.html). |
4 | * Initial Developer: H2 Group |
5 | */ |
6 | package org.h2.store; |
7 | |
8 | import java.io.EOFException; |
9 | import java.io.IOException; |
10 | import java.io.InputStream; |
11 | import java.io.Reader; |
12 | import org.h2.util.IOUtils; |
13 | |
14 | /** |
15 | * This class is backed by an input stream and supports reading values and |
16 | * variable size data. |
17 | */ |
18 | public class DataReader extends Reader { |
19 | |
20 | private final InputStream in; |
21 | |
22 | /** |
23 | * Create a new data reader. |
24 | * |
25 | * @param in the input stream |
26 | */ |
27 | public DataReader(InputStream in) { |
28 | this.in = in; |
29 | } |
30 | |
31 | /** |
32 | * Read a byte. |
33 | * |
34 | * @return the byte |
35 | */ |
36 | public byte readByte() throws IOException { |
37 | int x = in.read(); |
38 | if (x < 0) { |
39 | throw new FastEOFException(); |
40 | } |
41 | return (byte) x; |
42 | } |
43 | |
44 | /** |
45 | * Read a variable size integer. |
46 | * |
47 | * @return the value |
48 | */ |
49 | public int readVarInt() throws IOException { |
50 | int b = readByte(); |
51 | if (b >= 0) { |
52 | return b; |
53 | } |
54 | int x = b & 0x7f; |
55 | b = readByte(); |
56 | if (b >= 0) { |
57 | return x | (b << 7); |
58 | } |
59 | x |= (b & 0x7f) << 7; |
60 | b = readByte(); |
61 | if (b >= 0) { |
62 | return x | (b << 14); |
63 | } |
64 | x |= (b & 0x7f) << 14; |
65 | b = readByte(); |
66 | if (b >= 0) { |
67 | return x | b << 21; |
68 | } |
69 | return x | ((b & 0x7f) << 21) | (readByte() << 28); |
70 | } |
71 | |
72 | /** |
73 | * Read a variable size long. |
74 | * |
75 | * @return the value |
76 | */ |
77 | public long readVarLong() throws IOException { |
78 | long x = readByte(); |
79 | if (x >= 0) { |
80 | return x; |
81 | } |
82 | x &= 0x7f; |
83 | for (int s = 7;; s += 7) { |
84 | long b = readByte(); |
85 | x |= (b & 0x7f) << s; |
86 | if (b >= 0) { |
87 | return x; |
88 | } |
89 | } |
90 | } |
91 | |
92 | /** |
93 | * Read an integer. |
94 | * |
95 | * @return the value |
96 | */ |
97 | // public int readInt() throws IOException { |
98 | // return (read() << 24) + ((read() & 0xff) << 16) + |
99 | // ((read() & 0xff) << 8) + (read() & 0xff); |
100 | //} |
101 | |
102 | /** |
103 | * Read a long. |
104 | * |
105 | * @return the value |
106 | */ |
107 | // public long readLong() throws IOException { |
108 | // return ((long) (readInt()) << 32) + (readInt() & 0xffffffffL); |
109 | // } |
110 | |
111 | /** |
112 | * Read a number of bytes. |
113 | * |
114 | * @param buff the target buffer |
115 | * @param len the number of bytes to read |
116 | */ |
117 | public void readFully(byte[] buff, int len) throws IOException { |
118 | int got = IOUtils.readFully(in, buff, len); |
119 | if (got < len) { |
120 | throw new FastEOFException(); |
121 | } |
122 | } |
123 | |
124 | /** |
125 | * Read a string from the stream. |
126 | * |
127 | * @return the string |
128 | */ |
129 | public String readString() throws IOException { |
130 | int len = readVarInt(); |
131 | return readString(len); |
132 | } |
133 | |
134 | private String readString(int len) throws IOException { |
135 | char[] chars = new char[len]; |
136 | for (int i = 0; i < len; i++) { |
137 | chars[i] = readChar(); |
138 | } |
139 | return new String(chars); |
140 | } |
141 | |
142 | /** |
143 | * Read one character from the input stream. |
144 | * |
145 | * @return the character |
146 | */ |
147 | private char readChar() throws IOException { |
148 | int x = readByte() & 0xff; |
149 | if (x < 0x80) { |
150 | return (char) x; |
151 | } else if (x >= 0xe0) { |
152 | return (char) (((x & 0xf) << 12) + |
153 | ((readByte() & 0x3f) << 6) + |
154 | (readByte() & 0x3f)); |
155 | } else { |
156 | return (char) (((x & 0x1f) << 6) + |
157 | (readByte() & 0x3f)); |
158 | } |
159 | } |
160 | |
161 | @Override |
162 | public void close() throws IOException { |
163 | // ignore |
164 | } |
165 | |
166 | @Override |
167 | public int read(char[] buff, int off, int len) throws IOException { |
168 | int i = 0; |
169 | try { |
170 | for (; i < len; i++) { |
171 | buff[i] = readChar(); |
172 | } |
173 | return len; |
174 | } catch (EOFException e) { |
175 | return i; |
176 | } |
177 | } |
178 | |
179 | /** |
180 | * Constructing such an EOF exception is fast, because the stack trace is |
181 | * not filled in. If used in a static context, this will also avoid |
182 | * classloader memory leaks. |
183 | */ |
184 | static class FastEOFException extends EOFException { |
185 | |
186 | private static final long serialVersionUID = 1L; |
187 | |
188 | @Override |
189 | public synchronized Throwable fillInStackTrace() { |
190 | return null; |
191 | } |
192 | |
193 | } |
194 | |
195 | } |