diff --git a/ByteSource.java b/ByteSource.java
new file mode 100644
index 0000000..b12a807
--- /dev/null
+++ b/ByteSource.java
@@ -0,0 +1,758 @@
+/*
+ * Copyright (C) 2012 The Guava Authors
+ *
+ * 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.google.common.io;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.io.ByteStreams.createBuffer;
+import static com.google.common.io.ByteStreams.skipUpTo;
+
+import com.google.common.annotations.Beta;
+import com.google.common.annotations.GwtIncompatible;
+import com.google.common.base.Ascii;
+import com.google.common.base.Optional;
+import com.google.common.collect.ImmutableList;
+import com.google.common.hash.Funnels;
+import com.google.common.hash.HashCode;
+import com.google.common.hash.HashFunction;
+import com.google.common.hash.Hasher;
+import com.google.errorprone.annotations.CanIgnoreReturnValue;
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.Reader;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Iterator;
+import org.checkerframework.checker.nullness.qual.Nullable;
+
+/**
+ * A readable source of bytes, such as a file. Unlike an {@link InputStream}, a {@code ByteSource}
+ * is not an open, stateful stream for input that can be read and closed. Instead, it is an
+ * immutable supplier of {@code InputStream} instances.
+ *
+ *
{@code ByteSource} provides two kinds of methods:
+ *
+ *
+ * - Methods that return a stream: These methods should return a new, independent
+ * instance each time they are called. The caller is responsible for ensuring that the
+ * returned stream is closed.
+ *
- Convenience methods: These are implementations of common operations that are
+ * typically implemented by opening a stream using one of the methods in the first category,
+ * doing something and finally closing the stream that was opened.
+ *
+ *
+ * Note: In general, {@code ByteSource} is intended to be used for "file-like" sources
+ * that provide streams that are:
+ *
+ *
+ * - Finite: Many operations, such as {@link #size()} and {@link #read()}, will either
+ * block indefinitely or fail if the source creates an infinite stream.
+ *
- Non-destructive: A destructive stream will consume or otherwise alter the
+ * bytes of the source as they are read from it. A source that provides such streams will not
+ * be reusable, and operations that read from the stream (including {@link #size()}, in some
+ * implementations) will prevent further operations from completing as expected.
+ *
+ *
+ * @since 14.0
+ * @author Colin Decker
+ */
+@GwtIncompatible
+@ElementTypesAreNonnullByDefault
+public abstract class ByteSource {
+ /** Constructor for use by subclasses. */
+ protected ByteSource() {}
+ /**
+ * Returns a {@link CharSource} view of this byte source that decodes bytes read from this source
+ * as characters using the given {@link Charset}.
+ *
+ * If {@link CharSource#asByteSource} is called on the returned source with the same charset,
+ * the default implementation of this method will ensure that the original {@code ByteSource} is
+ * returned, rather than round-trip encoding. Subclasses that override this method should behave
+ * the same way.
+ */
+ public CharSource asCharSource(Charset charset) {
+ return new AsCharSource(charset);
+ }
+
+ /**
+ * Opens a new {@link InputStream} for reading from this source. This method returns a new,
+ * independent stream each time it is called.
+ *
+ *
The caller is responsible for ensuring that the returned stream is closed.
+ *
+ * @throws IOException if an I/O error occurs while opening the stream
+ */
+ public abstract InputStream openStream() throws IOException;
+
+ /**
+ * Opens a new buffered {@link InputStream} for reading from this source. The returned stream is
+ * not required to be a {@link BufferedInputStream} in order to allow implementations to simply
+ * delegate to {@link #openStream()} when the stream returned by that method does not benefit from
+ * additional buffering (for example, a {@code ByteArrayInputStream}). This method returns a new,
+ * independent stream each time it is called.
+ *
+ *
The caller is responsible for ensuring that the returned stream is closed.
+ *
+ * @throws IOException if an I/O error occurs while opening the stream
+ * @since 15.0 (in 14.0 with return type {@link BufferedInputStream})
+ */
+ public InputStream openBufferedStream() throws IOException {
+ InputStream in = openStream();
+ return (in instanceof BufferedInputStream)
+ ? (BufferedInputStream) in
+ : new BufferedInputStream(in);
+ }
+
+ /**
+ * Returns a view of a slice of this byte source that is at most {@code length} bytes long
+ * starting at the given {@code offset}. If {@code offset} is greater than the size of this
+ * source, the returned source will be empty. If {@code offset + length} is greater than the size
+ * of this source, the returned source will contain the slice starting at {@code offset} and
+ * ending at the end of this source.
+ *
+ * @throws IllegalArgumentException if {@code offset} or {@code length} is negative
+ */
+ public ByteSource slice(long offset, long length) {
+ return new SlicedByteSource(offset, length);
+ }
+
+ /**
+ * Returns whether the source has zero bytes. The default implementation first checks {@link
+ * #sizeIfKnown}, returning true if it's known to be zero and false if it's known to be non-zero.
+ * If the size is not known, it falls back to opening a stream and checking for EOF.
+ *
+ *
Note that, in cases where {@code sizeIfKnown} returns zero, it is possible that bytes
+ * are actually available for reading. (For example, some special files may return a size of 0
+ * despite actually having content when read.) This means that a source may return {@code true}
+ * from {@code isEmpty()} despite having readable content.
+ *
+ * @throws IOException if an I/O error occurs
+ * @since 15.0
+ */
+ public boolean isEmpty() throws IOException {
+ Optional sizeIfKnown = sizeIfKnown();
+ if (sizeIfKnown.isPresent()) {
+ return sizeIfKnown.get() == 0L;
+ }
+ Closer closer = Closer.create();
+ try {
+ InputStream in = closer.register(openStream());
+ return in.read() == -1;
+ } catch (Throwable e) {
+ throw closer.rethrow(e);
+ } finally {
+ closer.close();
+ }
+ }
+
+ /**
+ * Returns the size of this source in bytes, if the size can be easily determined without actually
+ * opening the data stream.
+ *
+ * The default implementation returns {@link Optional#absent}. Some sources, such as a file,
+ * may return a non-absent value. Note that in such cases, it is possible that this method
+ * will return a different number of bytes than would be returned by reading all of the bytes (for
+ * example, some special files may return a size of 0 despite actually having content when read).
+ *
+ *
Additionally, for mutable sources such as files, a subsequent read may return a different
+ * number of bytes if the contents are changed.
+ *
+ * @since 19.0
+ */
+ @Beta
+ public Optional sizeIfKnown() {
+ return Optional.absent();
+ }
+
+ /**
+ * Returns the size of this source in bytes, even if doing so requires opening and traversing an
+ * entire stream. To avoid a potentially expensive operation, see {@link #sizeIfKnown}.
+ *
+ * The default implementation calls {@link #sizeIfKnown} and returns the value if present. If
+ * absent, it will fall back to a heavyweight operation that will open a stream, read (or {@link
+ * InputStream#skip(long) skip}, if possible) to the end of the stream and return the total number
+ * of bytes that were read.
+ *
+ *
Note that for some sources that implement {@link #sizeIfKnown} to provide a more efficient
+ * implementation, it is possible that this method will return a different number of bytes
+ * than would be returned by reading all of the bytes (for example, some special files may return
+ * a size of 0 despite actually having content when read).
+ *
+ *
In either case, for mutable sources such as files, a subsequent read may return a different
+ * number of bytes if the contents are changed.
+ *
+ * @throws IOException if an I/O error occurs while reading the size of this source
+ */
+ public long size() throws IOException {
+ Optional sizeIfKnown = sizeIfKnown();
+ if (sizeIfKnown.isPresent()) {
+ return sizeIfKnown.get();
+ }
+
+ Closer closer = Closer.create();
+ try {
+ InputStream in = closer.register(openStream());
+ return countBySkipping(in);
+ } catch (IOException e) {
+ // skip may not be supported... at any rate, try reading
+ } finally {
+ closer.close();
+ }
+
+ closer = Closer.create();
+ try {
+ InputStream in = closer.register(openStream());
+ return ByteStreams.exhaust(in);
+ } catch (Throwable e) {
+ throw closer.rethrow(e);
+ } finally {
+ closer.close();
+ }
+ }
+
+ /** Counts the bytes in the given input stream using skip if possible. */
+ private long countBySkipping(InputStream in) throws IOException {
+ long count = 0;
+ long skipped;
+ while ((skipped = skipUpTo(in, Integer.MAX_VALUE)) > 0) {
+ count += skipped;
+ }
+ return count;
+ }
+
+ /**
+ * Copies the contents of this byte source to the given {@code OutputStream}. Does not close
+ * {@code output}.
+ *
+ * @return the number of bytes copied
+ * @throws IOException if an I/O error occurs while reading from this source or writing to {@code
+ * output}
+ */
+ @CanIgnoreReturnValue
+ public long copyTo(OutputStream output) throws IOException {
+ checkNotNull(output);
+
+ Closer closer = Closer.create();
+ try {
+ InputStream in = closer.register(openStream());
+ return ByteStreams.copy(in, output);
+ } catch (Throwable e) {
+ throw closer.rethrow(e);
+ } finally {
+ closer.close();
+ }
+ }
+
+ /**
+ * Copies the contents of this byte source to the given {@code ByteSink}.
+ *
+ * @return the number of bytes copied
+ * @throws IOException if an I/O error occurs while reading from this source or writing to {@code
+ * sink}
+ */
+ @CanIgnoreReturnValue
+ public long copyTo(ByteSink sink) throws IOException {
+ checkNotNull(sink);
+
+ Closer closer = Closer.create();
+ try {
+ InputStream in = closer.register(openStream());
+ OutputStream out = closer.register(sink.openStream());
+ return ByteStreams.copy(in, out);
+ } catch (Throwable e) {
+ throw closer.rethrow(e);
+ } finally {
+ closer.close();
+ }
+ }
+
+ /**
+ * Reads the full contents of this byte source as a byte array.
+ *
+ * @throws IOException if an I/O error occurs while reading from this source
+ */
+ public byte[] read() throws IOException {
+ Closer closer = Closer.create();
+ try {
+ InputStream in = closer.register(openStream());
+ Optional size = sizeIfKnown();
+ return size.isPresent()
+ ? ByteStreams.toByteArray(in, size.get())
+ : ByteStreams.toByteArray(in);
+ } catch (Throwable e) {
+ throw closer.rethrow(e);
+ } finally {
+ closer.close();
+ }
+ }
+
+ /**
+ * Reads the contents of this byte source using the given {@code processor} to process bytes as
+ * they are read. Stops when all bytes have been read or the consumer returns {@code false}.
+ * Returns the result produced by the processor.
+ *
+ * @throws IOException if an I/O error occurs while reading from this source or if {@code
+ * processor} throws an {@code IOException}
+ * @since 16.0
+ */
+ @Beta
+ @CanIgnoreReturnValue // some processors won't return a useful result
+ public T read(ByteProcessor processor) throws IOException {
+ checkNotNull(processor);
+
+ Closer closer = Closer.create();
+ try {
+ InputStream in = closer.register(openStream());
+ return ByteStreams.readBytes(in, processor);
+ } catch (Throwable e) {
+ throw closer.rethrow(e);
+ } finally {
+ closer.close();
+ }
+ }
+
+ /**
+ * Hashes the contents of this byte source using the given hash function.
+ *
+ * @throws IOException if an I/O error occurs while reading from this source
+ */
+ public HashCode hash(HashFunction hashFunction) throws IOException {
+ Hasher hasher = hashFunction.newHasher();
+ copyTo(Funnels.asOutputStream(hasher));
+ return hasher.hash();
+ }
+
+ /**
+ * Checks that the contents of this byte source are equal to the contents of the given byte
+ * source.
+ *
+ * @throws IOException if an I/O error occurs while reading from this source or {@code other}
+ */
+ public boolean contentEquals(ByteSource other) throws IOException {
+ checkNotNull(other);
+
+ byte[] buf1 = createBuffer();
+ byte[] buf2 = createBuffer();
+
+ Closer closer = Closer.create();
+ try {
+ InputStream in1 = closer.register(openStream());
+ InputStream in2 = closer.register(other.openStream());
+ while (true) {
+ int read1 = ByteStreams.read(in1, buf1, 0, buf1.length);
+ int read2 = ByteStreams.read(in2, buf2, 0, buf2.length);
+ if (read1 != read2 || !Arrays.equals(buf1, buf2)) {
+ return false;
+ } else if (read1 != buf1.length) {
+ return true;
+ }
+ }
+ } catch (Throwable e) {
+ throw closer.rethrow(e);
+ } finally {
+ closer.close();
+ }
+ }
+
+ /**
+ * Concatenates multiple {@link ByteSource} instances into a single source. Streams returned from
+ * the source will contain the concatenated data from the streams of the underlying sources.
+ *
+ * Only one underlying stream will be open at a time. Closing the concatenated stream will
+ * close the open underlying stream.
+ *
+ * @param sources the sources to concatenate
+ * @return a {@code ByteSource} containing the concatenated data
+ * @since 15.0
+ */
+ public static ByteSource concat(Iterable extends ByteSource> sources) {
+ return new ConcatenatedByteSource(sources);
+ }
+
+ /**
+ * Concatenates multiple {@link ByteSource} instances into a single source. Streams returned from
+ * the source will contain the concatenated data from the streams of the underlying sources.
+ *
+ *
Only one underlying stream will be open at a time. Closing the concatenated stream will
+ * close the open underlying stream.
+ *
+ *
Note: The input {@code Iterator} will be copied to an {@code ImmutableList} when this method
+ * is called. This will fail if the iterator is infinite and may cause problems if the iterator
+ * eagerly fetches data for each source when iterated (rather than producing sources that only
+ * load data through their streams). Prefer using the {@link #concat(Iterable)} overload if
+ * possible.
+ *
+ * @param sources the sources to concatenate
+ * @return a {@code ByteSource} containing the concatenated data
+ * @throws NullPointerException if any of {@code sources} is {@code null}
+ * @since 15.0
+ */
+ public static ByteSource concat(Iterator extends ByteSource> sources) {
+ return concat(ImmutableList.copyOf(sources));
+ }
+
+ /**
+ * Concatenates multiple {@link ByteSource} instances into a single source. Streams returned from
+ * the source will contain the concatenated data from the streams of the underlying sources.
+ *
+ *
Only one underlying stream will be open at a time. Closing the concatenated stream will
+ * close the open underlying stream.
+ *
+ * @param sources the sources to concatenate
+ * @return a {@code ByteSource} containing the concatenated data
+ * @throws NullPointerException if any of {@code sources} is {@code null}
+ * @since 15.0
+ */
+ public static ByteSource concat(ByteSource... sources) {
+ return concat(ImmutableList.copyOf(sources));
+ }
+
+ /**
+ * Returns a view of the given byte array as a {@link ByteSource}. To view only a specific range
+ * in the array, use {@code ByteSource.wrap(b).slice(offset, length)}.
+ *
+ *
Note that the given byte array may be passed directly to methods on, for example, {@code
+ * OutputStream} (when {@code copyTo(OutputStream)} is called on the resulting {@code
+ * ByteSource}). This could allow a malicious {@code OutputStream} implementation to modify the
+ * contents of the array, but provides better performance in the normal case.
+ *
+ * @since 15.0 (since 14.0 as {@code ByteStreams.asByteSource(byte[])}).
+ */
+ public static ByteSource wrap(byte[] b) {
+ return new ByteArrayByteSource(b);
+ }
+
+ /**
+ * Returns an immutable {@link ByteSource} that contains no bytes.
+ *
+ * @since 15.0
+ */
+ public static ByteSource empty() {
+ return EmptyByteSource.INSTANCE;
+ }
+
+ /**
+ * A char source that reads bytes from this source and decodes them as characters using a charset.
+ */
+ class AsCharSource extends CharSource {
+
+ final Charset charset;
+
+ AsCharSource(Charset charset) {
+ this.charset = checkNotNull(charset);
+ }
+
+ @Override
+ public ByteSource asByteSource(Charset charset) {
+ if (charset.equals(this.charset)) {
+ return ByteSource.this;
+ }
+ return super.asByteSource(charset);
+ }
+
+ @Override
+ public Reader openStream() throws IOException {
+ return new InputStreamReader(ByteSource.this.openStream(), charset);
+ }
+
+ @Override
+ public String read() throws IOException {
+ // Reading all the data as a byte array is more efficient than the default read()
+ // implementation because:
+ // 1. the string constructor can avoid an extra copy most of the time by correctly sizing the
+ // internal char array (hard to avoid using StringBuilder)
+ // 2. we avoid extra copies into temporary buffers altogether
+ // The downside is that this will cause us to store the file bytes in memory twice for a short
+ // amount of time.
+ return new String(ByteSource.this.read(), charset);
+ }
+
+ @Override
+ public String toString() {
+ return ByteSource.this.toString() + ".asCharSource(" + charset + ")";
+ }
+ }
+
+ /** A view of a subsection of the containing byte source. */
+ private final class SlicedByteSource extends ByteSource {
+
+ final long offset;
+ final long length;
+
+ SlicedByteSource(long offset, long length) {
+ checkArgument(offset >= 0, "offset (%s) may not be negative", offset);
+ checkArgument(length >= 0, "length (%s) may not be negative", length);
+ this.offset = offset;
+ this.length = length;
+ }
+
+ @Override
+ public InputStream openStream() throws IOException {
+ return sliceStream(ByteSource.this.openStream());
+ }
+
+ @Override
+ public InputStream openBufferedStream() throws IOException {
+ return sliceStream(ByteSource.this.openBufferedStream());
+ }
+
+ private InputStream sliceStream(InputStream in) throws IOException {
+ if (offset > 0) {
+ long skipped;
+ try {
+ skipped = ByteStreams.skipUpTo(in, offset);
+ } catch (Throwable e) {
+ Closer closer = Closer.create();
+ closer.register(in);
+ try {
+ throw closer.rethrow(e);
+ } finally {
+ closer.close();
+ }
+ }
+
+ if (skipped < offset) {
+ // offset was beyond EOF
+ in.close();
+ return new ByteArrayInputStream(new byte[0]);
+ }
+ }
+ return ByteStreams.limit(in, length);
+ }
+
+ @Override
+ public ByteSource slice(long offset, long length) {
+ checkArgument(offset >= 0, "offset (%s) may not be negative", offset);
+ checkArgument(length >= 0, "length (%s) may not be negative", length);
+ long maxLength = this.length - offset;
+ return maxLength <= 0
+ ? ByteSource.empty()
+ : ByteSource.this.slice(this.offset + offset, Math.min(length, maxLength));
+ }
+
+ @Override
+ public boolean isEmpty() throws IOException {
+ return length == 0 || super.isEmpty();
+ }
+
+ @Override
+ public Optional sizeIfKnown() {
+ Optional optionalUnslicedSize = ByteSource.this.sizeIfKnown();
+ if (optionalUnslicedSize.isPresent()) {
+ long unslicedSize = optionalUnslicedSize.get();
+ long off = Math.min(offset, unslicedSize);
+ return Optional.of(Math.min(length, unslicedSize - off));
+ }
+ return Optional.absent();
+ }
+
+ @Override
+ public String toString() {
+ return ByteSource.this.toString() + ".slice(" + offset + ", " + length + ")";
+ }
+ }
+
+ private static class ByteArrayByteSource extends
+ ByteSource
+ {
+
+ final byte[] bytes;
+ final int offset;
+ final int length;
+
+ ByteArrayByteSource(byte[] bytes) {
+ this(bytes, 0, bytes.length);
+ }
+
+ // NOTE: Preconditions are enforced by slice, the only non-trivial caller.
+ ByteArrayByteSource(byte[] bytes, int offset, int length) {
+ this.bytes = bytes;
+ this.offset = offset;
+ this.length = length;
+ }
+
+ @Override
+ public InputStream openStream() {
+ return new ByteArrayInputStream(bytes, offset, length);
+ }
+
+ @Override
+ public InputStream openBufferedStream() {
+ return openStream();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return length == 0;
+ }
+
+ @Override
+ public long size() {
+ return length;
+ }
+
+ @Override
+ public Optional sizeIfKnown() {
+ return Optional.of((long) length);
+ }
+
+ @Override
+ public byte[] read() {
+ return Arrays.copyOfRange(bytes, offset, offset + length);
+ }
+
+ @SuppressWarnings("CheckReturnValue") // it doesn't matter what processBytes returns here
+ @Override
+ @ParametricNullness
+ public T read(ByteProcessor processor) throws IOException {
+ processor.processBytes(bytes, offset, length);
+ return processor.getResult();
+ }
+
+ @Override
+ public long copyTo(OutputStream output) throws IOException {
+ output.write(bytes, offset, length);
+ return length;
+ }
+
+ @Override
+ public HashCode hash(HashFunction hashFunction) throws IOException {
+ return hashFunction.hashBytes(bytes, offset, length);
+ }
+
+ @Override
+ public ByteSource slice(long offset, long length) {
+ checkArgument(offset >= 0, "offset (%s) may not be negative", offset);
+ checkArgument(length >= 0, "length (%s) may not be negative", length);
+
+ offset = Math.min(offset, this.length);
+ length = Math.min(length, this.length - offset);
+ int newOffset = this.offset + (int) offset;
+ return new ByteArrayByteSource(bytes, newOffset, (int) length);
+ }
+
+ @Override
+ public String toString() {
+ return "ByteSource.wrap("
+ + Ascii.truncate(BaseEncoding.base16().encode(bytes, offset, length), 30, "...")
+ + ")";
+ }
+ }
+
+ private static final class EmptyByteSource extends ByteArrayByteSource {
+
+ static final EmptyByteSource INSTANCE = new EmptyByteSource();
+
+ EmptyByteSource() {
+ super(new byte[0]);
+ }
+
+ @Override
+ public CharSource asCharSource(Charset charset) {
+ checkNotNull(charset);
+ return CharSource.empty();
+ }
+
+ @Override
+ public byte[] read() {
+ return bytes; // length is 0, no need to clone
+ }
+
+ @Override
+ public String toString() {
+ return "ByteSource.empty()";
+ }
+ }
+
+ private static final class ConcatenatedByteSource extends ByteSource {
+
+ final Iterable extends ByteSource> sources;
+
+ ConcatenatedByteSource(Iterable extends ByteSource> sources) {
+ this.sources = checkNotNull(sources);
+ }
+
+ @Override
+ public InputStream openStream() throws IOException {
+ return new MultiInputStream(sources.iterator());
+ }
+
+ @Override
+ public boolean isEmpty() throws IOException {
+ for (ByteSource source : sources) {
+ if (!source.isEmpty()) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public Optional sizeIfKnown() {
+ if (!(sources instanceof Collection)) {
+ // Infinite Iterables can cause problems here. Of course, it's true that most of the other
+ // methods on this class also have potential problems with infinite Iterables. But unlike
+ // those, this method can cause issues even if the user is dealing with a (finite) slice()
+ // of this source, since the slice's sizeIfKnown() method needs to know the size of the
+ // underlying source to know what its size actually is.
+ return Optional.absent();
+ }
+ long result = 0L;
+ for (ByteSource source : sources) {
+ Optional sizeIfKnown = source.sizeIfKnown();
+ if (!sizeIfKnown.isPresent()) {
+ return Optional.absent();
+ }
+ result += sizeIfKnown.get();
+ if (result < 0) {
+ // Overflow (or one or more sources that returned a negative size, but all bets are off in
+ // that case)
+ // Can't represent anything higher, and realistically there probably isn't anything that
+ // can actually be done anyway with the supposed 8+ exbibytes of data the source is
+ // claiming to have if we get here, so just stop.
+ return Optional.of(Long.MAX_VALUE);
+ }
+ }
+ return Optional.of(result);
+ }
+
+ @Override
+ public long size() throws IOException {
+ long result = 0L;
+ for (ByteSource source : sources) {
+ result += source.size();
+ if (result < 0) {
+ // Overflow (or one or more sources that returned a negative size, but all bets are off in
+ // that case)
+ // Can't represent anything higher, and realistically there probably isn't anything that
+ // can actually be done anyway with the supposed 8+ exbibytes of data the source is
+ // claiming to have if we get here, so just stop.
+ return Long.MAX_VALUE;
+ }
+ }
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "ByteSource.concat(" + sources + ")";
+ }
+ }
+}
diff --git a/ResourceLeak.java b/ResourceLeak.java
new file mode 100644
index 0000000..05bc073
--- /dev/null
+++ b/ResourceLeak.java
@@ -0,0 +1,177 @@
+package javacodechecker;
+
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Reader;
+
+class ResourceLeak {
+ public void process1() {
+
+ try {
+ PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("out.txt", true)));
+ out.println("the text");
+
+
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK
+ out.close(); //close() is in try clause
+
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ FileOutputStream in = new FileOutputStream("xanadu.txt");
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK
+ in.close();
+ } catch (IOException e) {
+ }
+
+ }
+
+ public void processk() {
+
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ PrintWriter out = null;
+
+
+ try {
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ out = new PrintWriter(new File(""));
+ out.println("the text");
+ } catch (IOException e) {
+ } finally {
+ if(true) {
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ out.close();
+ }
+ }
+ }
+
+ public void testExceptionBlock() throws IOException {
+
+ Reader reader = null;
+ try {
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ reader = new FileReader("");
+ } catch (FileNotFoundException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ //Need to fix this
+ reader.close();
+ } finally {
+ if (reader != null) {
+ try {
+ int k;
+ int t;
+ int kk;
+ int tt;
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ reader.close();
+ } catch (IOException e) {
+ }catch (IOException e) {
+ } catch (IOException e) {
+ } finally {
+
+ }
+ }
+ }
+ }
+
+ //Non-compliant code
+ //resource is not closed anywhere
+ public void process2() {
+
+ try {
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK
+ PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("out.txt", true)));
+ out.println("the text");
+ } catch (IOException e) {
+ }
+
+ }
+
+ public void process3() {
+
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ try (PrintWriter out2 = new PrintWriter(new File(""))) {
+// out2.println("the text");
+ } catch (IOException e) {
+ }
+
+ }
+
+ PrintWriter outk = null;
+
+ public void processK() {
+
+ try {
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ if(null != outk)
+ outk.close();
+ } catch (Exception e) {
+ }
+
+ }
+
+ public void processN() {
+ Closer closer = Closer.create();
+ try {
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ InputStream in = closer.register(openInputStream());
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ OutputStream out = closer.register(openOutputStream());
+ // do stuff
+ } catch (
+ Throwable e) {
+ // ensure that any checked exception types other than IOException that could be thrown are
+ // provided here, e.g. throw closer.rethrow(e, CheckedException.class);
+ throw closer.rethrow(e);
+ } finally {
+ closer.close();
+ }
+ }
+ public void processN1() {
+ Closer closer = Closer.create();
+ try {
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ OutputStream out = closer.register(openStream());
+ long written = ByteStreams.copy(input, out);
+ out.flush(); // https://code.google.com/p/guava-libraries/issues/detail?id=1330
+ return written;
+ } catch (Throwable e) {
+ throw closer.rethrow(e);
+ } finally {
+ closer.close();
+ }
+ }
+ public boolean contentEquals(ByteSource other) throws IOException {
+ checkNotNull(other);
+
+ byte[] buf1 = createBuffer();
+ byte[] buf2 = createBuffer();
+
+ Closer closer = Closer.create();
+ try {
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ InputStream in1 = closer.register(openStream());
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ InputStream in2 = closer.register(other.openStream());
+ while (true) {
+ int read1 = ByteStreams.read(in1, buf1, 0, buf1.length);
+ int read2 = ByteStreams.read(in2, buf2, 0, buf2.length);
+ if (read1 != read2 || !Arrays.equals(buf1, buf2)) {
+ return false;
+ } else if (read1 != buf1.length) {
+ return true;
+ }
+ }
+ } catch (Throwable e) {
+ throw closer.rethrow(e);
+ } finally {
+ closer.close();
+ }
+ }
+}
diff --git a/embold.yaml b/embold.yaml
new file mode 100644
index 0000000..3fdefad
--- /dev/null
+++ b/embold.yaml
@@ -0,0 +1,36 @@
+version: 1
+## Please visit https://docs.embold.io/v2-quick-start-guide/#update-configurations to know more
+#languages: 'JAVA,CPP'
+# Sources mention which Files/Dirs to be taken for Analysis
+sources:
+ #Files or Directories to be Excluded are mentioned in exclusions
+ exclusions:
+ - 'test'
+ - 'generated'
+ - 'mock'
+ - 'thirdparty'
+ - 'third-party'
+ - '3rd-party'
+ - '3rdparty'
+ - 'external'
+ - 'build'
+ - 'node_modules'
+ - 'assets'
+ - 'gulp'
+ - 'grunt'
+ - 'library'
+ - 'libs'
+ - '.git'
+ - 'demosubproject'
+
+#Specify modules you would like to enable or disable.
+modules:
+ - name: gamma_java
+ enabled: true
+ rules:
+ - key: 'EMB-JAVA-10'
+ enabled: false
+ - name: pmd
+ enabled: true
+
+## Please visit https://docs.embold.io/v2-quick-start-guide/#update-configurations to know more
diff --git a/src/main/java/BMW.java b/src/main/java/BMW.java
index ca02a03..98b1c66 100644
--- a/src/main/java/BMW.java
+++ b/src/main/java/BMW.java
@@ -9,7 +9,19 @@ public BMW(int gear, int speed,
public void setHeight(int newValue)
{
+ int a=0;
+ int b=0;
seatHeight = newValue;
+ try{
+ int a=10;b=0;c=0;
+
+ }catch(Exception e){
+ }
+ try{
+ int a=10;b=0;c=0;
+
+ }catch(Exception e){
+ }
}
public int getLength(String[] strings) {
@@ -19,10 +31,21 @@ public int getLength(String[] strings) {
for (String str : strings) {
length += str.length();
}
+ try{
+ int a=10;b=0;c=0;
+ }catch(Exception e){
+ e.printstacktrace();
+ }
return length;
}
-
+ public void process1() {
+ try{
+ //some statements
+ } catch(Exception e) {
+ logger.error("Error while processing");
+ }
+ }
@Override public String toString()
{
return (super.toString() + "\nseat height is "
diff --git a/src/main/java/Bike.java b/src/main/java/Bike.java
index 54709f4..64be36c 100644
--- a/src/main/java/Bike.java
+++ b/src/main/java/Bike.java
@@ -20,6 +20,7 @@ public void speedUp(int increment)
public String toString()
{
+ System.out.println("No of gears are " + gear );
return ("No of gears are " + gear + "\n"
+ "speed of bicycle is " + speed);
}
diff --git a/src/main/java/Car.java b/src/main/java/Car.java
index f3faaa6..221fc4b 100644
--- a/src/main/java/Car.java
+++ b/src/main/java/Car.java
@@ -6,8 +6,7 @@ public Car(int gear, int speed)
{
this.gear = gear;
this.speed = speed;
- }
-
+ }
public Car(){}
public void applyBrake(int decrement)
@@ -17,11 +16,20 @@ public void applyBrake(int decrement)
public void speedUp(int increment)
{
+ try{
+ in a=0,b=0;
+ }catch(){}
speed += increment;
+ try{
+ in a=0,b=0;
+ }catch(){}
}
public String toString()
{
+ try{
+ in a=0,b=0;
+ }catch(){}
return ("No of gears are " + gear + "\n"
+ "speed of bicycle is " + speed);
}
diff --git a/src/main/java/Category.java b/src/main/java/Category.java
index fa7667b..6479f83 100644
--- a/src/main/java/Category.java
+++ b/src/main/java/Category.java
@@ -11,8 +11,13 @@ public class Category extends Vehicle implements NewInterface {
final int finalfield = 1;
int x, y;
-
+private String[] color = {"black","green"};
public String getCategory() {
+ try{
+ int a=10;b=0;c=0;
+
+ }catch(Exception e){
+ }
return category;
}
@@ -24,6 +29,13 @@ public void setCategory(String category, int category_id) {
public void set(String category){
this.category=category;
}
+ public String[] getColor() {
+ return color;
+ }
+
+ public String[] getColorss() {
+ return this.color;
+ }
private int m_variable;
@@ -46,6 +58,8 @@ public boolean getCategoryId() {
}
final String stringValue = "Welcome";
+ final String stringValue1 = "Welcome";
+ final String stringValue2 = "Welcome";
String get_string() {
for (; true; )
@@ -57,7 +71,12 @@ public boolean diff(int x) {
this.x = x + 1;
else
this.x = x - 1;
-
+ System.out.println("X and Y are different");
+ if (true)
+ this.y = y + 1;
+ System.out.println("X and Y are different");
+ if (true)
+ this.y = y + 1;
System.out.println("X and Y are different");
return false;
}
@@ -65,15 +84,18 @@ public boolean diff(int x) {
public boolean same(int y) {
if (true)
this.y = y + 1;
- System.out.println("X and Y are same");
+
return true;
}
+ try{
+ int a=10;b=0;c=0;
+
+ }catch(Exception e){
+ }
boolean bar(int x, int y) {
return (x != y) ? diff(x) : same(y);
}
-
-
@Override
public void remove(Object o) throws RemoveException, EJBException {
diff --git a/src/main/java/Main.java b/src/main/java/Main.java
index 39c5d7a..c858812 100644
--- a/src/main/java/Main.java
+++ b/src/main/java/Main.java
@@ -22,7 +22,11 @@ public static void main(String[] args) {
int length = bmw.getLength(new String[]{"Welcome", "To", "Embold"});
LOGGER.info(mercedes.toString());
LOGGER.info(bmw.toString());
-
+ try{
+ int a=10;b=0;c=0;
+
+ }catch(Exception e){
+ }
Category category= new Category();
category.setCategory("FourWheeler",1);
boolean isSame = category.bar(5,5);
diff --git a/src/main/java/MyClass.java b/src/main/java/MyClass.java
index 040c3fc..4de36d7 100644
--- a/src/main/java/MyClass.java
+++ b/src/main/java/MyClass.java
@@ -3,6 +3,8 @@
public class MyClass implements SessionBean {
+
+
@Override
public void setSessionContext(SessionContext sessionContext) throws EJBException, RemoteException {
diff --git a/src/main/java/ResourceLeak.java b/src/main/java/ResourceLeak.java
new file mode 100644
index 0000000..94afb03
--- /dev/null
+++ b/src/main/java/ResourceLeak.java
@@ -0,0 +1,192 @@
+import com.google.common.io.ByteSource;
+import com.google.common.io.ByteStreams;
+import com.google.common.io.Closer;
+
+import java.io.*;
+import java.util.Arrays;
+
+class ResourceLeak {
+ public void process1() {
+
+ try {
+ PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("out.txt", true)));
+ out.println("the text");
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK
+ out.close(); //close() is in try clause
+
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ FileOutputStream in = new FileOutputStream("xanadu.txt");
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK
+ in.close();
+ } catch (IOException e) {
+ }
+
+ }
+
+ public void processk() {
+
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ PrintWriter out = null;
+ try {
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ out = new PrintWriter(new File(""));
+ out.println("the text");
+ } catch (IOException e) {
+ } finally {
+ if (true) {
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ out.close();
+ }
+ }
+ }
+
+ public void testExceptionBlock() throws IOException {
+
+ Reader reader = null;
+ try {
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ reader = new FileReader("");
+ } catch (FileNotFoundException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ //Need to fix this
+ reader.close();
+ } finally {
+ if (reader != null) {
+ try {
+ int k;
+ int t;
+ int kk;
+ int tt;
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ reader.close();
+ } catch (IOException e) {
+ } finally {
+
+ }
+ }
+ }
+ }
+
+ //Non-compliant code
+ //resource is not closed anywhere
+ public void process2() {
+
+ try {
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK
+ PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter("out.txt", true)));
+ out.println("the text");
+ } catch (IOException e) {
+ }
+
+ }
+
+ public void process3() {
+
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ try (PrintWriter out2 = new PrintWriter(new File(""))) {
+// out2.println("the text");
+ } catch (IOException e) {
+ }
+
+ }
+
+ PrintWriter outk = null;
+
+ public void processK() {
+
+ try {
+ // EMB-ISSUE: CodeIssueNames.RESOURCE_LEAK/no-detect
+ if (null != outk)
+ outk.close();
+ } catch (Exception e) {
+ }
+
+ }
+
+ public void processN() throws IOException {
+ Closer closer = Closer.create();
+ try {
+ InputStream in = closer.register(openInputStream());
+ OutputStream out = closer.register(openOutputStream());
+ // do stuff
+ } catch (
+ Throwable e) {
+ // ensure that any checked exception types other than IOException that could be thrown are
+ // provided here, e.g. throw closer.rethrow(e, CheckedException.class);
+ throw closer.rethrow(e);
+ } finally {
+ closer.close();
+ }
+ }
+
+ private OutputStream openOutputStream() {
+ return null;
+ }
+
+ public long processN1() throws IOException {
+ Closer closer = Closer.create();
+ try {
+ InputStream input = (InputStream) closer.register(openInputStream());
+ OutputStream out = closer.register(openStream());
+ long written = ByteStreams.copy(input, out);
+ out.flush(); // https://code.google.com/p/guava-libraries/issues/detail?id=1330
+ return written;
+ } catch (Throwable e) {
+ throw closer.rethrow(e);
+ } finally {
+ closer.close();
+ }
+}
+
+ private OutputStream openStream() {
+ return null;
+ }
+
+ private InputStream openStream1() {
+ return null;
+ }
+
+ private InputStream openInputStream() throws IOException {
+ ByteSource byteSource = new ByteSource() {
+ @Override
+ public InputStream openStream() throws IOException {
+ return null;
+ }
+ };
+ contentEquals(byteSource);
+ return null;
+ }
+
+ public boolean contentEquals(ByteSource other) throws IOException {
+ //checkNotNull(other);
+ byte[] buf1 = createBuffer();
+ byte[] buf2 = createBuffer();
+
+ Closer closer = Closer.create();
+ try {
+ InputStream in1 = closer.register(openStream1());
+ InputStream in2 = closer.register(other.openStream());
+ while (true) {
+ int read1 = ByteStreams.read(in1, buf1, 0, buf1.length);
+ int read2 = ByteStreams.read(in2, buf2, 0, buf2.length);
+ if (read1 != read2 || !Arrays.equals(buf1, buf2)) {
+ return false;
+ } else if (read1 != buf1.length) {
+ return true;
+ }
+ }
+
+
+ } catch (Throwable e) {
+ throw closer.rethrow(e);
+ } finally {
+ closer.close();
+ }
+ }
+
+ private byte[] createBuffer() {
+ return new byte[0];
+ }
+
+}
diff --git a/src/main/java/Vehicle.java b/src/main/java/Vehicle.java
index edda7f3..de1def5 100644
--- a/src/main/java/Vehicle.java
+++ b/src/main/java/Vehicle.java
@@ -1,3 +1,5 @@
+
+
public abstract class Vehicle extends Object {
int isValid;
public abstract void setCategory(String category, int category_id);