001/*
002 *  Copyright 2017 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.workspaces.cmis;
017
018import java.io.FilterInputStream;
019import java.io.IOException;
020import java.io.InputStream;
021import java.math.BigInteger;
022
023import org.apache.chemistry.opencmis.commons.exceptions.CmisRuntimeException;
024
025/**
026 * Copied from openCMIS Server Development Guide
027 *
028 */
029public class CmisContentRangeInputStream extends FilterInputStream
030{
031    private static final int BUFFER_SIZE = 4096;
032
033    private long _offset;
034    private long _length;
035    private long _remaining;
036
037    /**
038     * create a RangeInputStream
039     * @param stream stream
040     * @param offset offset
041     * @param length length
042     */
043    public CmisContentRangeInputStream(InputStream stream, BigInteger offset, BigInteger length)
044    {
045        super(stream);
046
047        this._offset = offset != null ? offset.longValue() : 0;
048        this._length = length != null ? length.longValue() : Long.MAX_VALUE;
049
050        this._remaining = this._length;
051
052        if (this._offset > 0)
053        {
054            skipBytes();
055        }
056    }
057
058    private void skipBytes()
059    {
060        long remainingSkipBytes = _offset;
061
062        try
063        {
064            while (remainingSkipBytes > 0)
065            {
066                long skipped = super.skip(remainingSkipBytes);
067                remainingSkipBytes -= skipped;
068
069                if (skipped == 0)
070                {
071                    // stream might not support skipping
072                    skipBytesByReading(remainingSkipBytes);
073                    break;
074                }
075            }
076        }
077        catch (IOException e)
078        {
079            throw new CmisRuntimeException("Skipping the stream failed!", e);
080        }
081    }
082
083    private void skipBytesByReading(long remainingSkipBytes)
084    {
085        long usedRemainingSkipBytes = remainingSkipBytes;
086        try
087        {
088            final byte[] buffer = new byte[BUFFER_SIZE];
089            while (usedRemainingSkipBytes > 0)
090            {
091                long skipped = super.read(buffer, 0, (int) Math.min(buffer.length, usedRemainingSkipBytes));
092                if (skipped == -1)
093                {
094                    break;
095                }
096
097                usedRemainingSkipBytes -= skipped;
098            }
099        }
100        catch (IOException e)
101        {
102            throw new CmisRuntimeException("Reading the stream failed!", e);
103        }
104    }
105
106    @Override
107    public boolean markSupported()
108    {
109        return false;
110    }
111
112    @Override
113    public long skip(long n) throws IOException
114    {
115        if (_remaining <= 0)
116        {
117            return 0;
118        }
119
120        long skipped = super.skip(n);
121        _remaining -= skipped;
122
123        return skipped;
124    }
125
126    @Override
127    public int available() throws IOException
128    {
129        if (_remaining <= 0)
130        {
131            return 0;
132        }
133
134        int avail = super.available();
135
136        if (_remaining < avail)
137        {
138            return (int) _remaining;
139        }
140
141        return avail;
142    }
143
144    @Override
145    public int read() throws IOException
146    {
147        if (_remaining <= 0)
148        {
149            return -1;
150        }
151
152        _remaining--;
153
154        return super.read();
155    }
156
157    @Override
158    public int read(byte[] b, int off, int len) throws IOException
159    {
160        if (_remaining <= 0)
161        {
162            return -1;
163        }
164
165        int readBytes = super.read(b, off, (int) Math.min(len, _remaining));
166        if (readBytes == -1)
167        {
168            return -1;
169        }
170
171        _remaining -= readBytes;
172
173        return readBytes;
174    }
175
176    @Override
177    public int read(byte[] b) throws IOException
178    {
179        return read(b, 0, b.length);
180    }
181}