b26126b7447d7a0601c7034b988cf52b1a5e0d85
[controller.git] / opendaylight / md-sal / sal-clustering-commons / src / main / java / org / opendaylight / controller / cluster / io / ChunkedInputStream.java
1 /*
2  * Copyright (c) 2019 PANTHEON.tech, s.r.o. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.controller.cluster.io;
9
10 import static java.util.Objects.requireNonNull;
11
12 import java.io.InputStream;
13 import java.util.Iterator;
14
15 final class ChunkedInputStream extends InputStream {
16     private final Iterator<byte[]> remainingChunks;
17
18     private byte[] currentChunk;
19     private int currentLimit;
20     private int currentOffset;
21     private int available;
22
23     ChunkedInputStream(final int size, final Iterator<byte[]> iterator) {
24         remainingChunks = requireNonNull(iterator);
25         currentChunk = remainingChunks.next();
26         currentLimit = currentChunk.length;
27         available = size;
28     }
29
30     @Override
31     public int available() {
32         return available;
33     }
34
35     @Override
36     public int read() {
37         if (currentChunk == null) {
38             return -1;
39         }
40
41         int ret = currentChunk[currentOffset] & 0xff;
42         consumeBytes(1);
43         return ret;
44     }
45
46     @Override
47     @SuppressWarnings("checkstyle:ParameterName")
48     public int read(final byte[] b) {
49         return read(b, 0, b.length);
50     }
51
52     @Override
53     @SuppressWarnings("checkstyle:ParameterName")
54     public int read(final byte[] b, final int off, final int len) {
55         if (len < 0) {
56             throw new IndexOutOfBoundsException();
57         }
58         if (currentChunk == null) {
59             return -1;
60         }
61
62         final int result = Math.min(available, len);
63         int toOffset = off;
64         int toCopy = result;
65
66         while (toCopy != 0) {
67             final int count = currentBytes(toCopy);
68             System.arraycopy(currentChunk, currentOffset, b, toOffset, count);
69             consumeBytes(count);
70             toOffset += count;
71             toCopy -= count;
72         }
73
74         return result;
75     }
76
77     @Override
78     @SuppressWarnings("checkstyle:ParameterName")
79     public long skip(final long n) {
80         final int result = (int) Math.min(available, n);
81
82         int toSkip = result;
83         while (toSkip != 0) {
84             final int count = currentBytes(toSkip);
85             consumeBytes(count);
86             toSkip -= count;
87         }
88
89         return result;
90     }
91
92     private int currentBytes(final int desired) {
93         return Math.min(desired, currentLimit - currentOffset);
94     }
95
96     private void consumeBytes(final int count) {
97         currentOffset += count;
98         available -= count;
99
100         if (currentOffset == currentLimit) {
101             if (remainingChunks.hasNext()) {
102                 currentChunk = remainingChunks.next();
103                 currentLimit = currentChunk.length;
104             } else {
105                 currentChunk = null;
106                 currentLimit = 0;
107             }
108             currentOffset = 0;
109         }
110     }
111 }