All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.marklogic.io.ChunkedInputStream Maven / Gradle / Ivy

/*
 * Copyright 2003-2018 MarkLogic Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.marklogic.io;

import java.io.IOException;
import java.io.InputStream;

public class ChunkedInputStream extends InputStream {
    private InputStream stream;
    private int chunkSize; // size of a chunk
    private int position; // current position in a chunk
 
    private boolean bof = true;  // begin of stream
    private boolean eof = false; // end of stream
    private boolean closed = false;

    public ChunkedInputStream(InputStream in) throws IOException {
        if (in == null) {
            throw new IllegalArgumentException("Input stream cannot be null");
        }
        this.stream = in;
        this.position = 0;
    }
    
    @Override
    public int read() throws IOException {
        if (closed) {
            throw new IOException("Attempted read from closed stream.");
        }
        if (eof) {
            return -1;
        } 
        if (position >= chunkSize) {
            nextChunk();
            if (eof) { 
                return -1;
            }
        }
        position++;
        return stream.read();
    }

    @Override
    public int read (byte[] b, int off, int len) throws IOException {
        if (closed) {
            throw new IOException("Steam is closed");
        }

        if (eof) { 
            return -1;
        }
        if (position >= chunkSize) {
            nextChunk();
            if (eof) { 
                return -1;
            }
        }
        len = Math.min(len, chunkSize - position);
        int count = stream.read(b, off, len);
        position += count;
        return count;
    }

    @Override
    public int read (byte[] b) throws IOException {
        return read(b, 0, b.length);
    }

    private void nextChunk() throws IOException {
        if (!bof) {
            decodeChunkTrailer();
        }
        decodeChunkHeader();
        bof = false;
        position = 0;
        if (chunkSize == 0) {
            eof = true;
        }
    }

    private void decodeChunkHeader() throws IOException {
        int len = 0;
        int ch = -1;
        for (;;) {
            switch (ch = stream.read()) {
            case -1: 
                chunkSize = len;
                return;
            case '\n': 
                break;
            case '\r': 
                continue;
            case '0': case '1': case '2': case '3': case '4':
            case '5': case '6': case '7': case '8': case '9':
                len = (len * 16) + (ch - '0');
                continue;  
            case 'a': case 'b': case 'c': case 'd': case 'e':
            case 'f':
              len = (len * 16) + (10 + ch - 'a');
              continue;
            case 'A': case 'B': case 'C': case 'D': case 'E':
            case 'F':
              len = (len * 16) + (10 + ch - 'A');
              continue;
            default:
                for (;;) {
                    switch (ch = stream.read()) {
                    case -1:
                        chunkSize = len;
                        return;
                    case '\n':
                        break;
                    default:
                        continue;
                    }
                    break;
                }
                break;
            }
            break;
        }
        chunkSize = len;
        position = 0;
    }
    
    private void decodeChunkTrailer() throws IOException {
        int cr = stream.read();
        int lf = stream.read();
        if ((cr != '\r') || (lf != '\n')) { 
            throw new IOException(
                "CRLF expected at end of chunk: " + cr + "/" + lf);
        }
    }

    public void close() throws IOException {
        if (!closed) {
            try {
                if (!eof) {
                    byte buffer[] = new byte[1024];
                    while (stream.read(buffer) >= 0) {
                        ;
                    }
                }
            } finally {
                eof = true;
                closed = true;
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy