001package ezvcard.util;
002
003import java.io.BufferedInputStream;
004import java.io.ByteArrayOutputStream;
005import java.io.IOException;
006import java.io.InputStream;
007import java.io.InputStreamReader;
008import java.io.Reader;
009import java.nio.charset.Charset;
010import java.nio.file.Files;
011import java.nio.file.Path;
012
013/*
014 Copyright (c) 2012-2023, Michael Angstadt
015 All rights reserved.
016
017 Redistribution and use in source and binary forms, with or without
018 modification, are permitted provided that the following conditions are met: 
019
020 1. Redistributions of source code must retain the above copyright notice, this
021 list of conditions and the following disclaimer. 
022 2. Redistributions in binary form must reproduce the above copyright notice,
023 this list of conditions and the following disclaimer in the documentation
024 and/or other materials provided with the distribution. 
025
026 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
027 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
028 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
029 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
030 ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
031 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
032 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
033 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
034 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
035 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
036
037 The views and conclusions contained in the software and documentation are those
038 of the authors and should not be interpreted as representing official policies, 
039 either expressed or implied, of the FreeBSD Project.
040 */
041
042/**
043 * Gets the entire contents of an input stream or a file.
044 * @author Michael Angstadt
045 */
046public class Gobble {
047        private final Path file;
048        private final InputStream in;
049        private final Reader reader;
050
051        /**
052         * Gets the contents of a file.
053         * @param file the file
054         */
055        public Gobble(Path file) {
056                this(file, null, null);
057        }
058
059        /**
060         * Gets the contents of an input stream.
061         * @param in the input stream
062         */
063        public Gobble(InputStream in) {
064                this(null, in, null);
065        }
066
067        /**
068         * Gets the contents of a reader.
069         * @param reader the reader
070         */
071        public Gobble(Reader reader) {
072                this(null, null, reader);
073        }
074
075        private Gobble(Path file, InputStream in, Reader reader) {
076                this.file = file;
077                this.in = in;
078                this.reader = reader;
079        }
080
081        /**
082         * Gets the stream contents as a string. If something other than a
083         * {@link Reader} was passed into this class's constructor, this method
084         * decodes the stream data using the system's default character encoding.
085         * @return the string
086         * @throws IOException if there was a problem reading from the stream
087         */
088        public String asString() throws IOException {
089                return asString(Charset.defaultCharset());
090        }
091
092        /**
093         * Gets the stream contents as a string.
094         * @param charset the character set to decode the stream data with (this
095         * parameter is ignored if a {@link Reader} was passed into this class's
096         * constructor)
097         * @return the string
098         * @throws IOException if there was a problem reading from the stream
099         */
100        public String asString(Charset charset) throws IOException {
101                Reader reader = buildReader(charset);
102                return consumeReader(reader);
103        }
104
105        /**
106         * Gets the stream contents as a byte array.
107         * @return the byte array
108         * @throws IOException if there was a problem reading from the stream
109         * @throws IllegalStateException if a {@link Reader} object was passed into
110         * this class's constructor
111         */
112        public byte[] asByteArray() throws IOException {
113                if (reader != null) {
114                        throw new IllegalStateException("Cannot get raw bytes from a Reader object.");
115                }
116
117                InputStream in = buildInputStream();
118                return consumeInputStream(in);
119        }
120
121        private Reader buildReader(Charset charset) throws IOException {
122                return (reader == null) ? new InputStreamReader(buildInputStream(), charset) : reader;
123        }
124
125        private InputStream buildInputStream() throws IOException {
126                return (in == null) ? new BufferedInputStream(Files.newInputStream(file)) : in;
127        }
128
129        private String consumeReader(Reader reader) throws IOException {
130                StringBuilder sb = new StringBuilder();
131                char[] buffer = new char[4096];
132                int read;
133                try {
134                        while ((read = reader.read(buffer)) != -1) {
135                                sb.append(buffer, 0, read);
136                        }
137                } finally {
138                        reader.close();
139                }
140                return sb.toString();
141        }
142
143        private byte[] consumeInputStream(InputStream in) throws IOException {
144                ByteArrayOutputStream out = new ByteArrayOutputStream();
145                byte[] buffer = new byte[4096];
146                int read;
147                try {
148                        while ((read = in.read(buffer)) != -1) {
149                                out.write(buffer, 0, read);
150                        }
151                } finally {
152                        in.close();
153                }
154                return out.toByteArray();
155        }
156}