0
|
1 //
|
|
2 // MessagePack for Java
|
|
3 //
|
|
4 // Copyright (C) 2009 - 2013 FURUHASHI Sadayuki
|
|
5 //
|
|
6 // Licensed under the Apache License, Version 2.0 (the "License");
|
|
7 // you may not use this file except in compliance with the License.
|
|
8 // 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 package org.msgpack.io;
|
|
19
|
|
20 import java.io.IOException;
|
|
21 import java.io.EOFException;
|
|
22 import java.util.LinkedList;
|
|
23 import java.util.Iterator;
|
|
24 import java.util.NoSuchElementException;
|
|
25 import java.nio.ByteBuffer;
|
|
26
|
|
27 public class LinkedBufferInput extends AbstractInput {
|
|
28 LinkedList<ByteBuffer> link;
|
|
29
|
|
30 int writable;
|
|
31
|
|
32 private int nextAdvance;
|
|
33
|
|
34 private byte[] tmpBuffer;
|
|
35
|
|
36 private ByteBuffer tmpByteBuffer;
|
|
37
|
|
38 private final int bufferSize;
|
|
39
|
|
40 public LinkedBufferInput(int bufferSize) {
|
|
41 this.link = new LinkedList<ByteBuffer>();
|
|
42 this.writable = -1;
|
|
43 this.tmpBuffer = new byte[8];
|
|
44 this.tmpByteBuffer = ByteBuffer.wrap(tmpBuffer);
|
|
45 this.bufferSize = bufferSize;
|
|
46 }
|
|
47
|
|
48 public int read(byte[] b, int off, int len) throws EOFException {
|
|
49 if (link.isEmpty()) {
|
|
50 return 0;
|
|
51 }
|
|
52 int olen = len;
|
|
53 while (true) {
|
|
54 ByteBuffer bb = link.getFirst();
|
|
55 if (len < bb.remaining()) {
|
|
56 bb.get(b, off, len);
|
|
57 incrReadByteCount(len);
|
|
58 return olen;
|
|
59 }
|
|
60 int rem = bb.remaining();
|
|
61 bb.get(b, off, rem);
|
|
62 incrReadByteCount(rem);
|
|
63 len -= rem;
|
|
64 off += rem;
|
|
65 if (!removeFirstLink(bb)) {
|
|
66 break;
|
|
67 }
|
|
68 }
|
|
69 return olen - len;
|
|
70 }
|
|
71
|
|
72 public boolean tryRefer(BufferReferer ref, int len) throws IOException {
|
|
73 ByteBuffer bb = null;
|
|
74 try {
|
|
75 bb = link.getFirst();
|
|
76 } catch(NoSuchElementException e) {}
|
|
77 if (bb == null) {
|
|
78 throw new EndOfBufferException();
|
|
79 } else if (bb.remaining() < len) {
|
|
80 return false;
|
|
81 }
|
|
82 boolean success = false;
|
|
83 int pos = bb.position();
|
|
84 int lim = bb.limit();
|
|
85 try {
|
|
86 bb.limit(pos + len);
|
|
87 ref.refer(bb, true);
|
|
88 incrReadByteCount(len);
|
|
89 success = true;
|
|
90 } finally {
|
|
91 bb.limit(lim);
|
|
92 if (success) {
|
|
93 bb.position(pos + len);
|
|
94 } else {
|
|
95 bb.position(pos);
|
|
96 }
|
|
97 if (bb.remaining() == 0) {
|
|
98 removeFirstLink(bb);
|
|
99 }
|
|
100 }
|
|
101 return true;
|
|
102 }
|
|
103
|
|
104 public byte readByte() throws EOFException {
|
|
105 ByteBuffer bb = null;
|
|
106 try {
|
|
107 bb = link.getFirst();
|
|
108 } catch(NoSuchElementException e) {}
|
|
109 if (bb == null || bb.remaining() == 0) {
|
|
110 throw new EndOfBufferException();
|
|
111 }
|
|
112 byte result = bb.get();
|
|
113 incrReadOneByteCount();
|
|
114 if (bb.remaining() == 0) {
|
|
115 removeFirstLink(bb);
|
|
116 }
|
|
117 return result;
|
|
118 }
|
|
119
|
|
120 public void advance() {
|
|
121 if (link.isEmpty()) {
|
|
122 return;
|
|
123 }
|
|
124 int len = nextAdvance;
|
|
125 ByteBuffer bb;
|
|
126 while (true) {
|
|
127 bb = link.getFirst();
|
|
128 if (len < bb.remaining()) {
|
|
129 bb.position(bb.position() + len);
|
|
130 break;
|
|
131 }
|
|
132 len -= bb.remaining();
|
|
133 bb.position(bb.position() + bb.remaining());
|
|
134 if (!removeFirstLink(bb)) {
|
|
135 break;
|
|
136 }
|
|
137 }
|
|
138 incrReadByteCount(nextAdvance);
|
|
139 nextAdvance = 0;
|
|
140 }
|
|
141
|
|
142 private boolean removeFirstLink(ByteBuffer first) {
|
|
143 if (link.size() == 1) {
|
|
144 if (writable >= 0) {
|
|
145 first.position(0);
|
|
146 first.limit(0);
|
|
147 writable = first.capacity();
|
|
148 return false;
|
|
149 } else {
|
|
150 link.removeFirst();
|
|
151 return false;
|
|
152 }
|
|
153 } else {
|
|
154 link.removeFirst();
|
|
155 return true;
|
|
156 }
|
|
157 }
|
|
158
|
|
159 private void requireMore(int n) throws EOFException {
|
|
160 int off = 0;
|
|
161 for (ByteBuffer bb : link) {
|
|
162 if (n <= bb.remaining()) {
|
|
163 int pos = bb.position();
|
|
164 bb.get(tmpBuffer, off, n);
|
|
165 bb.position(pos);
|
|
166 return;
|
|
167 }
|
|
168 int rem = bb.remaining();
|
|
169 int pos = bb.position();
|
|
170 bb.get(tmpBuffer, off, rem);
|
|
171 bb.position(pos);
|
|
172 n -= rem;
|
|
173 off += rem;
|
|
174 }
|
|
175 throw new EndOfBufferException();
|
|
176 }
|
|
177
|
|
178 private ByteBuffer require(int n) throws EOFException {
|
|
179 ByteBuffer bb = null;
|
|
180 try {
|
|
181 bb = link.getFirst();
|
|
182 } catch(NoSuchElementException e) {}
|
|
183 if (bb == null) {
|
|
184 throw new EndOfBufferException();
|
|
185 }
|
|
186 if (n <= bb.remaining()) {
|
|
187 nextAdvance = n;
|
|
188 return bb;
|
|
189 } else {
|
|
190 requireMore(n);
|
|
191 nextAdvance = n;
|
|
192 return tmpByteBuffer;
|
|
193 }
|
|
194 }
|
|
195
|
|
196 public byte getByte() throws EOFException {
|
|
197 ByteBuffer bb = require(1);
|
|
198 return bb.get(bb.position());
|
|
199 }
|
|
200
|
|
201 public short getShort() throws EOFException {
|
|
202 ByteBuffer bb = require(2);
|
|
203 return bb.getShort(bb.position());
|
|
204 }
|
|
205
|
|
206 public int getInt() throws EOFException {
|
|
207 ByteBuffer bb = require(4);
|
|
208 return bb.getInt(bb.position());
|
|
209 }
|
|
210
|
|
211 public long getLong() throws EOFException {
|
|
212 ByteBuffer bb = require(8);
|
|
213 return bb.getLong(bb.position());
|
|
214 }
|
|
215
|
|
216 public float getFloat() throws EOFException {
|
|
217 ByteBuffer bb = require(4);
|
|
218 return bb.getFloat(bb.position());
|
|
219 }
|
|
220
|
|
221 public double getDouble() throws EOFException {
|
|
222 ByteBuffer bb = require(8);
|
|
223 return bb.getDouble(bb.position());
|
|
224 }
|
|
225
|
|
226 public void feed(byte[] b) {
|
|
227 feed(b, 0, b.length, false);
|
|
228 }
|
|
229
|
|
230 public void feed(byte[] b, boolean reference) {
|
|
231 feed(b, 0, b.length, reference);
|
|
232 }
|
|
233
|
|
234 public void feed(byte[] b, int off, int len) {
|
|
235 feed(b, off, len, false);
|
|
236 }
|
|
237
|
|
238 public void feed(byte[] b, int off, int len, boolean reference) {
|
|
239 if (reference) {
|
|
240 if (writable > 0 && link.getLast().remaining() == 0) {
|
|
241 link.add(link.size()-1, ByteBuffer.wrap(b, off, len));
|
|
242 return;
|
|
243 }
|
|
244 link.addLast(ByteBuffer.wrap(b, off, len));
|
|
245 writable = -1;
|
|
246 return;
|
|
247 }
|
|
248
|
|
249 ByteBuffer bb = null;
|
|
250 try {
|
|
251 bb = link.getLast();
|
|
252 } catch(NoSuchElementException e) {}
|
|
253 if (len <= writable) {
|
|
254 int pos = bb.position();
|
|
255 bb.position(bb.limit());
|
|
256 bb.limit(bb.limit() + len);
|
|
257 bb.put(b, off, len);
|
|
258 bb.position(pos);
|
|
259 writable = bb.capacity() - bb.limit();
|
|
260 return;
|
|
261 }
|
|
262
|
|
263 if (writable > 0) {
|
|
264 int pos = bb.position();
|
|
265 bb.position(bb.limit());
|
|
266 bb.limit(bb.limit() + writable);
|
|
267 bb.put(b, off, writable);
|
|
268 bb.position(pos);
|
|
269 off += writable;
|
|
270 len -= writable;
|
|
271 writable = 0;
|
|
272 }
|
|
273
|
|
274 int sz = Math.max(len, bufferSize);
|
|
275 ByteBuffer nb = ByteBuffer.allocate(sz);
|
|
276 nb.put(b, off, len);
|
|
277 nb.limit(len);
|
|
278 nb.position(0);
|
|
279 link.addLast(nb);
|
|
280 writable = sz - len;
|
|
281 }
|
|
282
|
|
283 public void feed(ByteBuffer b) {
|
|
284 feed(b, false);
|
|
285 }
|
|
286
|
|
287 public void feed(ByteBuffer buf, boolean reference) {
|
|
288 if (reference) {
|
|
289 if (writable > 0 && link.getLast().remaining() == 0) {
|
|
290 link.add(link.size()-1, buf);
|
|
291 return;
|
|
292 }
|
|
293 link.addLast(buf);
|
|
294 writable = -1;
|
|
295 return;
|
|
296 }
|
|
297
|
|
298 int rem = buf.remaining();
|
|
299
|
|
300 ByteBuffer bb = null;
|
|
301 try {
|
|
302 bb = link.getLast();
|
|
303 } catch(NoSuchElementException e) {}
|
|
304 if (rem <= writable) {
|
|
305 int pos = bb.position();
|
|
306 bb.position(bb.limit());
|
|
307 bb.limit(bb.limit() + rem);
|
|
308 bb.put(buf);
|
|
309 bb.position(pos);
|
|
310 writable = bb.capacity() - bb.limit();
|
|
311 return;
|
|
312 }
|
|
313
|
|
314 if (writable > 0) {
|
|
315 int pos = bb.position();
|
|
316 bb.position(bb.limit());
|
|
317 bb.limit(bb.limit() + writable);
|
|
318 buf.limit(writable);
|
|
319 bb.put(buf);
|
|
320 bb.position(pos);
|
|
321 rem -= writable;
|
|
322 buf.limit(buf.limit() + rem);
|
|
323 writable = 0;
|
|
324 }
|
|
325
|
|
326 int sz = Math.max(rem, bufferSize);
|
|
327 ByteBuffer nb = ByteBuffer.allocate(sz);
|
|
328 nb.put(buf);
|
|
329 nb.limit(rem);
|
|
330 nb.position(0);
|
|
331 link.addLast(nb);
|
|
332 writable = sz - rem;
|
|
333 }
|
|
334
|
|
335 public void clear() {
|
|
336 if (writable >= 0) {
|
|
337 ByteBuffer bb = link.getLast();
|
|
338 link.clear();
|
|
339 bb.position(0);
|
|
340 bb.limit(0);
|
|
341 link.addLast(bb);
|
|
342 writable = bb.capacity();
|
|
343 } else {
|
|
344 link.clear();
|
|
345 writable = -1;
|
|
346 }
|
|
347 }
|
|
348
|
|
349 public void copyReferencedBuffer() {
|
|
350 if (link.isEmpty()) {
|
|
351 return;
|
|
352 }
|
|
353
|
|
354 int size = 0;
|
|
355 for(ByteBuffer bb : link) {
|
|
356 size += bb.remaining();
|
|
357 }
|
|
358 if (size == 0) {
|
|
359 return;
|
|
360 }
|
|
361
|
|
362 if (writable >= 0) {
|
|
363 ByteBuffer last = link.removeLast();
|
|
364 byte[] copy = new byte[size - last.remaining()];
|
|
365 int off = 0;
|
|
366 for(ByteBuffer bb : link) {
|
|
367 int len = bb.remaining();
|
|
368 bb.get(copy, off, len);
|
|
369 off += len;
|
|
370 }
|
|
371 link.clear();
|
|
372 link.add(ByteBuffer.wrap(copy));
|
|
373 link.add(last);
|
|
374
|
|
375 } else {
|
|
376 byte[] copy = new byte[size];
|
|
377 int off = 0;
|
|
378 for(ByteBuffer bb : link) {
|
|
379 int len = bb.remaining();
|
|
380 bb.get(copy, off, len);
|
|
381 off += len;
|
|
382 }
|
|
383 link.clear();
|
|
384 link.add(ByteBuffer.wrap(copy));
|
|
385 writable = 0;
|
|
386 }
|
|
387 }
|
|
388
|
|
389 public int getSize() {
|
|
390 int size = 0;
|
|
391 for(ByteBuffer bb : link) {
|
|
392 size += bb.remaining();
|
|
393 }
|
|
394 return size;
|
|
395 }
|
|
396
|
|
397 public void close() {
|
|
398 }
|
|
399 }
|