summaryrefslogtreecommitdiffstats
path: root/guava/src/com/google/common/io
diff options
context:
space:
mode:
Diffstat (limited to 'guava/src/com/google/common/io')
-rw-r--r--guava/src/com/google/common/io/AppendableWriter.java117
-rw-r--r--guava/src/com/google/common/io/ByteArrayDataInput.java65
-rw-r--r--guava/src/com/google/common/io/ByteArrayDataOutput.java55
-rw-r--r--guava/src/com/google/common/io/ByteProcessor.java49
-rw-r--r--guava/src/com/google/common/io/ByteStreams.java871
-rw-r--r--guava/src/com/google/common/io/CharStreams.java441
-rw-r--r--guava/src/com/google/common/io/Closeables.java104
-rw-r--r--guava/src/com/google/common/io/CountingInputStream.java90
-rw-r--r--guava/src/com/google/common/io/CountingOutputStream.java59
-rw-r--r--guava/src/com/google/common/io/FileBackedOutputStream.java210
-rw-r--r--guava/src/com/google/common/io/Files.java780
-rw-r--r--guava/src/com/google/common/io/Flushables.java80
-rw-r--r--guava/src/com/google/common/io/InputSupplier.java40
-rw-r--r--guava/src/com/google/common/io/LimitInputStream.java104
-rw-r--r--guava/src/com/google/common/io/LineBuffer.java117
-rw-r--r--guava/src/com/google/common/io/LineProcessor.java45
-rw-r--r--guava/src/com/google/common/io/LineReader.java87
-rw-r--r--guava/src/com/google/common/io/LittleEndianDataInputStream.java232
-rw-r--r--guava/src/com/google/common/io/LittleEndianDataOutputStream.java164
-rw-r--r--guava/src/com/google/common/io/MultiInputStream.java115
-rw-r--r--guava/src/com/google/common/io/MultiReader.java90
-rw-r--r--guava/src/com/google/common/io/NullOutputStream.java38
-rw-r--r--guava/src/com/google/common/io/OutputSupplier.java40
-rw-r--r--guava/src/com/google/common/io/PatternFilenameFilter.java62
-rw-r--r--guava/src/com/google/common/io/Resources.java173
-rw-r--r--guava/src/com/google/common/io/package-info.java41
26 files changed, 4269 insertions, 0 deletions
diff --git a/guava/src/com/google/common/io/AppendableWriter.java b/guava/src/com/google/common/io/AppendableWriter.java
new file mode 100644
index 0000000..8033e46
--- /dev/null
+++ b/guava/src/com/google/common/io/AppendableWriter.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2006 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 java.io.Closeable;
+import java.io.Flushable;
+import java.io.IOException;
+import java.io.Writer;
+
+/**
+ * Writer that places all output on an {@link Appendable} target. If the target
+ * is {@link Flushable} or {@link Closeable}, flush()es and close()s will also
+ * be delegated to the target.
+ *
+ * @author Alan Green
+ * @author Sebastian Kanthak
+ * @since 1.0
+ */
+class AppendableWriter extends Writer {
+ private final Appendable target;
+ private boolean closed;
+
+ /**
+ * Creates a new writer that appends everything it writes to {@code target}.
+ *
+ * @param target target to which to append output
+ */
+ AppendableWriter(Appendable target) {
+ this.target = target;
+ }
+
+ /*
+ * Abstract methods from Writer
+ */
+
+ @Override public void write(char cbuf[], int off, int len)
+ throws IOException {
+ checkNotClosed();
+ // It turns out that creating a new String is usually as fast, or faster
+ // than wrapping cbuf in a light-weight CharSequence.
+ target.append(new String(cbuf, off, len));
+ }
+
+ @Override public void flush() throws IOException {
+ checkNotClosed();
+ if (target instanceof Flushable) {
+ ((Flushable) target).flush();
+ }
+ }
+
+ @Override public void close() throws IOException {
+ this.closed = true;
+ if (target instanceof Closeable) {
+ ((Closeable) target).close();
+ }
+ }
+
+ /*
+ * Override a few functions for performance reasons to avoid creating
+ * unnecessary strings.
+ */
+
+ @Override public void write(int c) throws IOException {
+ checkNotClosed();
+ target.append((char) c);
+ }
+
+ @Override public void write(String str) throws IOException {
+ checkNotClosed();
+ target.append(str);
+ }
+
+ @Override public void write(String str, int off, int len) throws IOException {
+ checkNotClosed();
+ // tricky: append takes start, end pair...
+ target.append(str, off, off + len);
+ }
+
+ @Override public Writer append(char c) throws IOException {
+ checkNotClosed();
+ target.append(c);
+ return this;
+ }
+
+ @Override public Writer append(CharSequence charSeq) throws IOException {
+ checkNotClosed();
+ target.append(charSeq);
+ return this;
+ }
+
+ @Override public Writer append(CharSequence charSeq, int start, int end)
+ throws IOException {
+ checkNotClosed();
+ target.append(charSeq, start, end);
+ return this;
+ }
+
+ private void checkNotClosed() throws IOException {
+ if (closed) {
+ throw new IOException("Cannot write to a closed writer.");
+ }
+ }
+}
diff --git a/guava/src/com/google/common/io/ByteArrayDataInput.java b/guava/src/com/google/common/io/ByteArrayDataInput.java
new file mode 100644
index 0000000..3f4a467
--- /dev/null
+++ b/guava/src/com/google/common/io/ByteArrayDataInput.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2009 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 java.io.DataInput;
+import java.io.IOException;
+
+/**
+ * An extension of {@code DataInput} for reading from in-memory byte arrays; its
+ * methods offer identical functionality but do not throw {@link IOException}.
+ *
+ * <p><b>Warning:<b> The caller is responsible for not attempting to read past
+ * the end of the array. If any method encounters the end of the array
+ * prematurely, it throws {@link IllegalStateException} to signify <i>programmer
+ * error</i>. This behavior is a technical violation of the supertype's
+ * contract, which specifies a checked exception.
+ *
+ * @author Kevin Bourrillion
+ * @since 1.0
+ */
+public interface ByteArrayDataInput extends DataInput {
+ @Override void readFully(byte b[]);
+
+ @Override void readFully(byte b[], int off, int len);
+
+ @Override int skipBytes(int n);
+
+ @Override boolean readBoolean();
+
+ @Override byte readByte();
+
+ @Override int readUnsignedByte();
+
+ @Override short readShort();
+
+ @Override int readUnsignedShort();
+
+ @Override char readChar();
+
+ @Override int readInt();
+
+ @Override long readLong();
+
+ @Override float readFloat();
+
+ @Override double readDouble();
+
+ @Override String readLine();
+
+ @Override String readUTF();
+}
diff --git a/guava/src/com/google/common/io/ByteArrayDataOutput.java b/guava/src/com/google/common/io/ByteArrayDataOutput.java
new file mode 100644
index 0000000..4d3dd97
--- /dev/null
+++ b/guava/src/com/google/common/io/ByteArrayDataOutput.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2009 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 java.io.DataOutput;
+import java.io.IOException;
+
+/**
+ * An extension of {@code DataOutput} for writing to in-memory byte arrays; its
+ * methods offer identical functionality but do not throw {@link IOException}.
+ *
+ * @author Jayaprabhakar Kadarkarai
+ * @since 1.0
+ */
+public interface ByteArrayDataOutput extends DataOutput {
+ @Override void write(int b);
+ @Override void write(byte b[]);
+ @Override void write(byte b[], int off, int len);
+ @Override void writeBoolean(boolean v);
+ @Override void writeByte(int v);
+ @Override void writeShort(int v);
+ @Override void writeChar(int v);
+ @Override void writeInt(int v);
+ @Override void writeLong(long v);
+ @Override void writeFloat(float v);
+ @Override void writeDouble(double v);
+ @Override void writeChars(String s);
+ @Override void writeUTF(String s);
+
+ /**
+ * @deprecated This method is dangerous as it discards the high byte of
+ * every character. For UTF-8, use {@code write(s.getBytes(Charsets.UTF_8))}.
+ */
+ @Deprecated @Override void writeBytes(String s);
+
+ /**
+ * Returns the contents that have been written to this instance,
+ * as a byte array.
+ */
+ byte[] toByteArray();
+}
diff --git a/guava/src/com/google/common/io/ByteProcessor.java b/guava/src/com/google/common/io/ByteProcessor.java
new file mode 100644
index 0000000..71953be
--- /dev/null
+++ b/guava/src/com/google/common/io/ByteProcessor.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2009 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 com.google.common.annotations.Beta;
+
+import java.io.IOException;
+
+/**
+ * A callback interface to process bytes from a stream.
+ *
+ * <p>{@link #processBytes} will be called for each line that is read, and
+ * should return {@code false} when you want to stop processing.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+@Beta
+public interface ByteProcessor<T> {
+ /**
+ * This method will be called for each chunk of bytes in an
+ * input stream. The implementation should process the bytes
+ * from {@code buf[off]} through {@code buf[off + len - 1]}
+ * (inclusive).
+ *
+ * @param buf the byte array containing the data to process
+ * @param off the initial offset into the array
+ * @param len the length of data to be processed
+ * @return true to continue processing, false to stop
+ */
+ boolean processBytes(byte[] buf, int off, int len) throws IOException;
+
+ /** Return the result of processing all the bytes. */
+ T getResult();
+}
diff --git a/guava/src/com/google/common/io/ByteStreams.java b/guava/src/com/google/common/io/ByteStreams.java
new file mode 100644
index 0000000..388504e
--- /dev/null
+++ b/guava/src/com/google/common/io/ByteStreams.java
@@ -0,0 +1,871 @@
+/*
+ * Copyright (C) 2007 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 com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+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 java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.channels.ReadableByteChannel;
+import java.nio.channels.WritableByteChannel;
+import java.util.Arrays;
+import java.util.zip.Checksum;
+
+/**
+ * Provides utility methods for working with byte arrays and I/O streams.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+@Beta
+public final class ByteStreams {
+ private static final int BUF_SIZE = 0x1000; // 4K
+
+ private ByteStreams() {}
+
+ /**
+ * Returns a factory that will supply instances of
+ * {@link ByteArrayInputStream} that read from the given byte array.
+ *
+ * @param b the input buffer
+ * @return the factory
+ */
+ public static InputSupplier<ByteArrayInputStream> newInputStreamSupplier(
+ byte[] b) {
+ return newInputStreamSupplier(b, 0, b.length);
+ }
+
+ /**
+ * Returns a factory that will supply instances of
+ * {@link ByteArrayInputStream} that read from the given byte array.
+ *
+ * @param b the input buffer
+ * @param off the offset in the buffer of the first byte to read
+ * @param len the maximum number of bytes to read from the buffer
+ * @return the factory
+ */
+ public static InputSupplier<ByteArrayInputStream> newInputStreamSupplier(
+ final byte[] b, final int off, final int len) {
+ return new InputSupplier<ByteArrayInputStream>() {
+ @Override
+ public ByteArrayInputStream getInput() {
+ return new ByteArrayInputStream(b, off, len);
+ }
+ };
+ }
+
+ /**
+ * Writes a byte array to an output stream from the given supplier.
+ *
+ * @param from the bytes to write
+ * @param to the output supplier
+ * @throws IOException if an I/O error occurs
+ */
+ public static void write(byte[] from,
+ OutputSupplier<? extends OutputStream> to) throws IOException {
+ Preconditions.checkNotNull(from);
+ boolean threw = true;
+ OutputStream out = to.getOutput();
+ try {
+ out.write(from);
+ threw = false;
+ } finally {
+ Closeables.close(out, threw);
+ }
+ }
+
+ /**
+ * Opens input and output streams from the given suppliers, copies all
+ * bytes from the input to the output, and closes the streams.
+ *
+ * @param from the input factory
+ * @param to the output factory
+ * @return the number of bytes copied
+ * @throws IOException if an I/O error occurs
+ */
+ public static long copy(InputSupplier<? extends InputStream> from,
+ OutputSupplier<? extends OutputStream> to) throws IOException {
+ int successfulOps = 0;
+ InputStream in = from.getInput();
+ try {
+ OutputStream out = to.getOutput();
+ try {
+ long count = copy(in, out);
+ successfulOps++;
+ return count;
+ } finally {
+ Closeables.close(out, successfulOps < 1);
+ successfulOps++;
+ }
+ } finally {
+ Closeables.close(in, successfulOps < 2);
+ }
+ }
+
+ /**
+ * Opens an input stream from the supplier, copies all bytes from the
+ * input to the output, and closes the input stream. Does not close
+ * or flush the output stream.
+ *
+ * @param from the input factory
+ * @param to the output stream to write to
+ * @return the number of bytes copied
+ * @throws IOException if an I/O error occurs
+ */
+ public static long copy(InputSupplier<? extends InputStream> from,
+ OutputStream to) throws IOException {
+ boolean threw = true;
+ InputStream in = from.getInput();
+ try {
+ long count = copy(in, to);
+ threw = false;
+ return count;
+ } finally {
+ Closeables.close(in, threw);
+ }
+ }
+
+ /**
+ * Opens an output stream from the supplier, copies all bytes from the input
+ * to the output, and closes the output stream. Does not close or flush the
+ * input stream.
+ *
+ * @param from the input stream to read from
+ * @param to the output factory
+ * @return the number of bytes copied
+ * @throws IOException if an I/O error occurs
+ * @since 10.0
+ */
+ public static long copy(InputStream from,
+ OutputSupplier<? extends OutputStream> to) throws IOException {
+ boolean threw = true;
+ OutputStream out = to.getOutput();
+ try {
+ long count = copy(from, out);
+ threw = false;
+ return count;
+ } finally {
+ Closeables.close(out, threw);
+ }
+ }
+
+ /**
+ * Copies all bytes from the input stream to the output stream.
+ * Does not close or flush either stream.
+ *
+ * @param from the input stream to read from
+ * @param to the output stream to write to
+ * @return the number of bytes copied
+ * @throws IOException if an I/O error occurs
+ */
+ public static long copy(InputStream from, OutputStream to)
+ throws IOException {
+ byte[] buf = new byte[BUF_SIZE];
+ long total = 0;
+ while (true) {
+ int r = from.read(buf);
+ if (r == -1) {
+ break;
+ }
+ to.write(buf, 0, r);
+ total += r;
+ }
+ return total;
+ }
+
+ /**
+ * Copies all bytes from the readable channel to the writable channel.
+ * Does not close or flush either channel.
+ *
+ * @param from the readable channel to read from
+ * @param to the writable channel to write to
+ * @return the number of bytes copied
+ * @throws IOException if an I/O error occurs
+ */
+ public static long copy(ReadableByteChannel from,
+ WritableByteChannel to) throws IOException {
+ ByteBuffer buf = ByteBuffer.allocate(BUF_SIZE);
+ long total = 0;
+ while (from.read(buf) != -1) {
+ buf.flip();
+ while (buf.hasRemaining()) {
+ total += to.write(buf);
+ }
+ buf.clear();
+ }
+ return total;
+ }
+
+ /**
+ * Reads all bytes from an input stream into a byte array.
+ * Does not close the stream.
+ *
+ * @param in the input stream to read from
+ * @return a byte array containing all the bytes from the stream
+ * @throws IOException if an I/O error occurs
+ */
+ public static byte[] toByteArray(InputStream in) throws IOException {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ copy(in, out);
+ return out.toByteArray();
+ }
+
+ /**
+ * Returns the data from a {@link InputStream} factory as a byte array.
+ *
+ * @param supplier the factory
+ * @throws IOException if an I/O error occurs
+ */
+ public static byte[] toByteArray(
+ InputSupplier<? extends InputStream> supplier) throws IOException {
+ boolean threw = true;
+ InputStream in = supplier.getInput();
+ try {
+ byte[] result = toByteArray(in);
+ threw = false;
+ return result;
+ } finally {
+ Closeables.close(in, threw);
+ }
+ }
+
+ /**
+ * Returns a new {@link ByteArrayDataInput} instance to read from the {@code
+ * bytes} array from the beginning.
+ */
+ public static ByteArrayDataInput newDataInput(byte[] bytes) {
+ return new ByteArrayDataInputStream(bytes);
+ }
+
+ /**
+ * Returns a new {@link ByteArrayDataInput} instance to read from the {@code
+ * bytes} array, starting at the given position.
+ *
+ * @throws IndexOutOfBoundsException if {@code start} is negative or greater
+ * than the length of the array
+ */
+ public static ByteArrayDataInput newDataInput(byte[] bytes, int start) {
+ Preconditions.checkPositionIndex(start, bytes.length);
+ return new ByteArrayDataInputStream(bytes, start);
+ }
+
+ private static class ByteArrayDataInputStream implements ByteArrayDataInput {
+ final DataInput input;
+
+ ByteArrayDataInputStream(byte[] bytes) {
+ this.input = new DataInputStream(new ByteArrayInputStream(bytes));
+ }
+
+ ByteArrayDataInputStream(byte[] bytes, int start) {
+ this.input = new DataInputStream(
+ new ByteArrayInputStream(bytes, start, bytes.length - start));
+ }
+
+ @Override public void readFully(byte b[]) {
+ try {
+ input.readFully(b);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public void readFully(byte b[], int off, int len) {
+ try {
+ input.readFully(b, off, len);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public int skipBytes(int n) {
+ try {
+ return input.skipBytes(n);
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public boolean readBoolean() {
+ try {
+ return input.readBoolean();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public byte readByte() {
+ try {
+ return input.readByte();
+ } catch (EOFException e) {
+ throw new IllegalStateException(e);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public int readUnsignedByte() {
+ try {
+ return input.readUnsignedByte();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public short readShort() {
+ try {
+ return input.readShort();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public int readUnsignedShort() {
+ try {
+ return input.readUnsignedShort();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public char readChar() {
+ try {
+ return input.readChar();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public int readInt() {
+ try {
+ return input.readInt();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public long readLong() {
+ try {
+ return input.readLong();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public float readFloat() {
+ try {
+ return input.readFloat();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public double readDouble() {
+ try {
+ return input.readDouble();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public String readLine() {
+ try {
+ return input.readLine();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+
+ @Override public String readUTF() {
+ try {
+ return input.readUTF();
+ } catch (IOException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+
+ /**
+ * Returns a new {@link ByteArrayDataOutput} instance with a default size.
+ */
+ public static ByteArrayDataOutput newDataOutput() {
+ return new ByteArrayDataOutputStream();
+ }
+
+ /**
+ * Returns a new {@link ByteArrayDataOutput} instance sized to hold
+ * {@code size} bytes before resizing.
+ *
+ * @throws IllegalArgumentException if {@code size} is negative
+ */
+ public static ByteArrayDataOutput newDataOutput(int size) {
+ Preconditions.checkArgument(size >= 0, "Invalid size: %s", size);
+ return new ByteArrayDataOutputStream(size);
+ }
+
+ @SuppressWarnings("deprecation") // for writeBytes
+ private static class ByteArrayDataOutputStream
+ implements ByteArrayDataOutput {
+
+ final DataOutput output;
+ final ByteArrayOutputStream byteArrayOutputSteam;
+
+ ByteArrayDataOutputStream() {
+ this(new ByteArrayOutputStream());
+ }
+
+ ByteArrayDataOutputStream(int size) {
+ this(new ByteArrayOutputStream(size));
+ }
+
+ ByteArrayDataOutputStream(ByteArrayOutputStream byteArrayOutputSteam) {
+ this.byteArrayOutputSteam = byteArrayOutputSteam;
+ output = new DataOutputStream(byteArrayOutputSteam);
+ }
+
+ @Override public void write(int b) {
+ try {
+ output.write(b);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void write(byte[] b) {
+ try {
+ output.write(b);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void write(byte[] b, int off, int len) {
+ try {
+ output.write(b, off, len);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeBoolean(boolean v) {
+ try {
+ output.writeBoolean(v);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeByte(int v) {
+ try {
+ output.writeByte(v);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeBytes(String s) {
+ try {
+ output.writeBytes(s);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeChar(int v) {
+ try {
+ output.writeChar(v);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeChars(String s) {
+ try {
+ output.writeChars(s);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeDouble(double v) {
+ try {
+ output.writeDouble(v);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeFloat(float v) {
+ try {
+ output.writeFloat(v);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeInt(int v) {
+ try {
+ output.writeInt(v);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeLong(long v) {
+ try {
+ output.writeLong(v);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeShort(int v) {
+ try {
+ output.writeShort(v);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public void writeUTF(String s) {
+ try {
+ output.writeUTF(s);
+ } catch (IOException impossible) {
+ throw new AssertionError(impossible);
+ }
+ }
+
+ @Override public byte[] toByteArray() {
+ return byteArrayOutputSteam.toByteArray();
+ }
+
+ }
+
+ // TODO(chrisn): Not all streams support skipping.
+ /** Returns the length of a supplied input stream, in bytes. */
+ public static long length(InputSupplier<? extends InputStream> supplier)
+ throws IOException {
+ long count = 0;
+ boolean threw = true;
+ InputStream in = supplier.getInput();
+ try {
+ while (true) {
+ // We skip only Integer.MAX_VALUE due to JDK overflow bugs.
+ long amt = in.skip(Integer.MAX_VALUE);
+ if (amt == 0) {
+ if (in.read() == -1) {
+ threw = false;
+ return count;
+ }
+ count++;
+ } else {
+ count += amt;
+ }
+ }
+ } finally {
+ Closeables.close(in, threw);
+ }
+ }
+
+ /**
+ * Returns true if the supplied input streams contain the same bytes.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ public static boolean equal(InputSupplier<? extends InputStream> supplier1,
+ InputSupplier<? extends InputStream> supplier2) throws IOException {
+ byte[] buf1 = new byte[BUF_SIZE];
+ byte[] buf2 = new byte[BUF_SIZE];
+
+ boolean threw = true;
+ InputStream in1 = supplier1.getInput();
+ try {
+ InputStream in2 = supplier2.getInput();
+ try {
+ while (true) {
+ int read1 = read(in1, buf1, 0, BUF_SIZE);
+ int read2 = read(in2, buf2, 0, BUF_SIZE);
+ if (read1 != read2 || !Arrays.equals(buf1, buf2)) {
+ threw = false;
+ return false;
+ } else if (read1 != BUF_SIZE) {
+ threw = false;
+ return true;
+ }
+ }
+ } finally {
+ Closeables.close(in2, threw);
+ }
+ } finally {
+ Closeables.close(in1, threw);
+ }
+ }
+
+ /**
+ * Attempts to read enough bytes from the stream to fill the given byte array,
+ * with the same behavior as {@link DataInput#readFully(byte[])}.
+ * Does not close the stream.
+ *
+ * @param in the input stream to read from.
+ * @param b the buffer into which the data is read.
+ * @throws EOFException if this stream reaches the end before reading all
+ * the bytes.
+ * @throws IOException if an I/O error occurs.
+ */
+ public static void readFully(InputStream in, byte[] b) throws IOException {
+ readFully(in, b, 0, b.length);
+ }
+
+ /**
+ * Attempts to read {@code len} bytes from the stream into the given array
+ * starting at {@code off}, with the same behavior as
+ * {@link DataInput#readFully(byte[], int, int)}. Does not close the
+ * stream.
+ *
+ * @param in the input stream to read from.
+ * @param b the buffer into which the data is read.
+ * @param off an int specifying the offset into the data.
+ * @param len an int specifying the number of bytes to read.
+ * @throws EOFException if this stream reaches the end before reading all
+ * the bytes.
+ * @throws IOException if an I/O error occurs.
+ */
+ public static void readFully(InputStream in, byte[] b, int off, int len)
+ throws IOException {
+ if (read(in, b, off, len) != len) {
+ throw new EOFException();
+ }
+ }
+
+ /**
+ * Discards {@code n} bytes of data from the input stream. This method
+ * will block until the full amount has been skipped. Does not close the
+ * stream.
+ *
+ * @param in the input stream to read from
+ * @param n the number of bytes to skip
+ * @throws EOFException if this stream reaches the end before skipping all
+ * the bytes
+ * @throws IOException if an I/O error occurs, or the stream does not
+ * support skipping
+ */
+ public static void skipFully(InputStream in, long n) throws IOException {
+ while (n > 0) {
+ long amt = in.skip(n);
+ if (amt == 0) {
+ // Force a blocking read to avoid infinite loop
+ if (in.read() == -1) {
+ throw new EOFException();
+ }
+ n--;
+ } else {
+ n -= amt;
+ }
+ }
+ }
+
+ /**
+ * Process the bytes of a supplied stream
+ *
+ * @param supplier the input stream factory
+ * @param processor the object to which to pass the bytes of the stream
+ * @return the result of the byte processor
+ * @throws IOException if an I/O error occurs
+ */
+ public static <T> T readBytes(InputSupplier<? extends InputStream> supplier,
+ ByteProcessor<T> processor) throws IOException {
+ byte[] buf = new byte[BUF_SIZE];
+ boolean threw = true;
+ InputStream in = supplier.getInput();
+ try {
+ int amt;
+ do {
+ amt = in.read(buf);
+ if (amt == -1) {
+ threw = false;
+ break;
+ }
+ } while (processor.processBytes(buf, 0, amt));
+ return processor.getResult();
+ } finally {
+ Closeables.close(in, threw);
+ }
+ }
+
+ /**
+ * Computes and returns the checksum value for a supplied input stream.
+ * The checksum object is reset when this method returns successfully.
+ *
+ * @param supplier the input stream factory
+ * @param checksum the checksum object
+ * @return the result of {@link Checksum#getValue} after updating the
+ * checksum object with all of the bytes in the stream
+ * @throws IOException if an I/O error occurs
+ */
+ public static long getChecksum(InputSupplier<? extends InputStream> supplier,
+ final Checksum checksum) throws IOException {
+ return readBytes(supplier, new ByteProcessor<Long>() {
+ @Override
+ public boolean processBytes(byte[] buf, int off, int len) {
+ checksum.update(buf, off, len);
+ return true;
+ }
+
+ @Override
+ public Long getResult() {
+ long result = checksum.getValue();
+ checksum.reset();
+ return result;
+ }
+ });
+ }
+
+ /**
+ * Computes the hash code of the data supplied by {@code supplier} using {@code
+ * hashFunction}.
+ *
+ * @param supplier the input stream factory
+ * @param hashFunction the hash function to use to hash the data
+ * @return the {@link HashCode} of all of the bytes in the input stream
+ * @throws IOException if an I/O error occurs
+ * @since 12.0
+ */
+ public static HashCode hash(
+ InputSupplier<? extends InputStream> supplier, HashFunction hashFunction)
+ throws IOException {
+ Hasher hasher = hashFunction.newHasher();
+ copy(supplier, Funnels.asOutputStream(hasher));
+ return hasher.hash();
+ }
+
+ /**
+ * Reads some bytes from an input stream and stores them into the buffer array
+ * {@code b}. This method blocks until {@code len} bytes of input data have
+ * been read into the array, or end of file is detected. The number of bytes
+ * read is returned, possibly zero. Does not close the stream.
+ *
+ * <p>A caller can detect EOF if the number of bytes read is less than
+ * {@code len}. All subsequent calls on the same stream will return zero.
+ *
+ * <p>If {@code b} is null, a {@code NullPointerException} is thrown. If
+ * {@code off} is negative, or {@code len} is negative, or {@code off+len} is
+ * greater than the length of the array {@code b}, then an
+ * {@code IndexOutOfBoundsException} is thrown. If {@code len} is zero, then
+ * no bytes are read. Otherwise, the first byte read is stored into element
+ * {@code b[off]}, the next one into {@code b[off+1]}, and so on. The number
+ * of bytes read is, at most, equal to {@code len}.
+ *
+ * @param in the input stream to read from
+ * @param b the buffer into which the data is read
+ * @param off an int specifying the offset into the data
+ * @param len an int specifying the number of bytes to read
+ * @return the number of bytes read
+ * @throws IOException if an I/O error occurs
+ */
+ public static int read(InputStream in, byte[] b, int off, int len)
+ throws IOException {
+ if (len < 0) {
+ throw new IndexOutOfBoundsException("len is negative");
+ }
+ int total = 0;
+ while (total < len) {
+ int result = in.read(b, off + total, len - total);
+ if (result == -1) {
+ break;
+ }
+ total += result;
+ }
+ return total;
+ }
+
+ /**
+ * Returns an {@link InputSupplier} that returns input streams from the
+ * an underlying supplier, where each stream starts at the given
+ * offset and is limited to the specified number of bytes.
+ *
+ * @param supplier the supplier from which to get the raw streams
+ * @param offset the offset in bytes into the underlying stream where
+ * the returned streams will start
+ * @param length the maximum length of the returned streams
+ * @throws IllegalArgumentException if offset or length are negative
+ */
+ public static InputSupplier<InputStream> slice(
+ final InputSupplier<? extends InputStream> supplier,
+ final long offset,
+ final long length) {
+ Preconditions.checkNotNull(supplier);
+ Preconditions.checkArgument(offset >= 0, "offset is negative");
+ Preconditions.checkArgument(length >= 0, "length is negative");
+ return new InputSupplier<InputStream>() {
+ @Override public InputStream getInput() throws IOException {
+ InputStream in = supplier.getInput();
+ if (offset > 0) {
+ try {
+ skipFully(in, offset);
+ } catch (IOException e) {
+ Closeables.closeQuietly(in);
+ throw e;
+ }
+ }
+ return new LimitInputStream(in, length);
+ }
+ };
+ }
+
+ /**
+ * Joins multiple {@link InputStream} suppliers into a single supplier.
+ * Streams returned from the supplier will contain the concatenated data from
+ * the streams of the underlying suppliers.
+ *
+ * <p>Only one underlying input stream will be open at a time. Closing the
+ * joined stream will close the open underlying stream.
+ *
+ * <p>Reading from the joined stream will throw a {@link NullPointerException}
+ * if any of the suppliers are null or return null.
+ *
+ * @param suppliers the suppliers to concatenate
+ * @return a supplier that will return a stream containing the concatenated
+ * stream data
+ */
+ public static InputSupplier<InputStream> join(final
+ Iterable<? extends InputSupplier<? extends InputStream>> suppliers) {
+ return new InputSupplier<InputStream>() {
+ @Override public InputStream getInput() throws IOException {
+ return new MultiInputStream(suppliers.iterator());
+ }
+ };
+ }
+
+ /** Varargs form of {@link #join(Iterable)}. */
+ public static InputSupplier<InputStream> join(
+ InputSupplier<? extends InputStream>... suppliers) {
+ return join(Arrays.asList(suppliers));
+ }
+}
diff --git a/guava/src/com/google/common/io/CharStreams.java b/guava/src/com/google/common/io/CharStreams.java
new file mode 100644
index 0000000..6a70375
--- /dev/null
+++ b/guava/src/com/google/common/io/CharStreams.java
@@ -0,0 +1,441 @@
+/*
+ * Copyright (C) 2007 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 com.google.common.annotations.Beta;
+import com.google.common.base.Charsets;
+import com.google.common.base.Preconditions;
+
+import java.io.Closeable;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.Writer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Provides utility methods for working with character streams.
+ *
+ * <p>All method parameters must be non-null unless documented otherwise.
+ *
+ * <p>Some of the methods in this class take arguments with a generic type of
+ * {@code Readable & Closeable}. A {@link java.io.Reader} implements both of
+ * those interfaces. Similarly for {@code Appendable & Closeable} and
+ * {@link java.io.Writer}.
+ *
+ * @author Chris Nokleberg
+ * @author Bin Zhu
+ * @since 1.0
+ */
+@Beta
+public final class CharStreams {
+ private static final int BUF_SIZE = 0x800; // 2K chars (4K bytes)
+
+ private CharStreams() {}
+
+ /**
+ * Returns a factory that will supply instances of {@link StringReader} that
+ * read a string value.
+ *
+ * @param value the string to read
+ * @return the factory
+ */
+ public static InputSupplier<StringReader> newReaderSupplier(
+ final String value) {
+ Preconditions.checkNotNull(value);
+ return new InputSupplier<StringReader>() {
+ @Override
+ public StringReader getInput() {
+ return new StringReader(value);
+ }
+ };
+ }
+
+ /**
+ * Returns a factory that will supply instances of {@link InputStreamReader},
+ * using the given {@link InputStream} factory and character set.
+ *
+ * @param in the factory that will be used to open input streams
+ * @param charset the charset used to decode the input stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @return the factory
+ */
+ public static InputSupplier<InputStreamReader> newReaderSupplier(
+ final InputSupplier<? extends InputStream> in, final Charset charset) {
+ Preconditions.checkNotNull(in);
+ Preconditions.checkNotNull(charset);
+ return new InputSupplier<InputStreamReader>() {
+ @Override
+ public InputStreamReader getInput() throws IOException {
+ return new InputStreamReader(in.getInput(), charset);
+ }
+ };
+ }
+
+ /**
+ * Returns a factory that will supply instances of {@link OutputStreamWriter},
+ * using the given {@link OutputStream} factory and character set.
+ *
+ * @param out the factory that will be used to open output streams
+ * @param charset the charset used to encode the output stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @return the factory
+ */
+ public static OutputSupplier<OutputStreamWriter> newWriterSupplier(
+ final OutputSupplier<? extends OutputStream> out, final Charset charset) {
+ Preconditions.checkNotNull(out);
+ Preconditions.checkNotNull(charset);
+ return new OutputSupplier<OutputStreamWriter>() {
+ @Override
+ public OutputStreamWriter getOutput() throws IOException {
+ return new OutputStreamWriter(out.getOutput(), charset);
+ }
+ };
+ }
+
+ /**
+ * Writes a character sequence (such as a string) to an appendable
+ * object from the given supplier.
+ *
+ * @param from the character sequence to write
+ * @param to the output supplier
+ * @throws IOException if an I/O error occurs
+ */
+ public static <W extends Appendable & Closeable> void write(CharSequence from,
+ OutputSupplier<W> to) throws IOException {
+ Preconditions.checkNotNull(from);
+ boolean threw = true;
+ W out = to.getOutput();
+ try {
+ out.append(from);
+ threw = false;
+ } finally {
+ Closeables.close(out, threw);
+ }
+ }
+
+ /**
+ * Opens {@link Readable} and {@link Appendable} objects from the
+ * given factories, copies all characters between the two, and closes
+ * them.
+ *
+ * @param from the input factory
+ * @param to the output factory
+ * @return the number of characters copied
+ * @throws IOException if an I/O error occurs
+ */
+ public static <R extends Readable & Closeable,
+ W extends Appendable & Closeable> long copy(InputSupplier<R> from,
+ OutputSupplier<W> to) throws IOException {
+ int successfulOps = 0;
+ R in = from.getInput();
+ try {
+ W out = to.getOutput();
+ try {
+ long count = copy(in, out);
+ successfulOps++;
+ return count;
+ } finally {
+ Closeables.close(out, successfulOps < 1);
+ successfulOps++;
+ }
+ } finally {
+ Closeables.close(in, successfulOps < 2);
+ }
+ }
+
+ /**
+ * Opens a {@link Readable} object from the supplier, copies all characters
+ * to the {@link Appendable} object, and closes the input. Does not close
+ * or flush the output.
+ *
+ * @param from the input factory
+ * @param to the object to write to
+ * @return the number of characters copied
+ * @throws IOException if an I/O error occurs
+ */
+ public static <R extends Readable & Closeable> long copy(
+ InputSupplier<R> from, Appendable to) throws IOException {
+ boolean threw = true;
+ R in = from.getInput();
+ try {
+ long count = copy(in, to);
+ threw = false;
+ return count;
+ } finally {
+ Closeables.close(in, threw);
+ }
+ }
+
+ /**
+ * Copies all characters between the {@link Readable} and {@link Appendable}
+ * objects. Does not close or flush either object.
+ *
+ * @param from the object to read from
+ * @param to the object to write to
+ * @return the number of characters copied
+ * @throws IOException if an I/O error occurs
+ */
+ public static long copy(Readable from, Appendable to) throws IOException {
+ CharBuffer buf = CharBuffer.allocate(BUF_SIZE);
+ long total = 0;
+ while (from.read(buf) != -1) {
+ buf.flip();
+ to.append(buf);
+ total += buf.remaining();
+ buf.clear();
+ }
+ return total;
+ }
+
+ /**
+ * Reads all characters from a {@link Readable} object into a {@link String}.
+ * Does not close the {@code Readable}.
+ *
+ * @param r the object to read from
+ * @return a string containing all the characters
+ * @throws IOException if an I/O error occurs
+ */
+ public static String toString(Readable r) throws IOException {
+ return toStringBuilder(r).toString();
+ }
+
+ /**
+ * Returns the characters from a {@link Readable} & {@link Closeable} object
+ * supplied by a factory as a {@link String}.
+ *
+ * @param supplier the factory to read from
+ * @return a string containing all the characters
+ * @throws IOException if an I/O error occurs
+ */
+ public static <R extends Readable & Closeable> String toString(
+ InputSupplier<R> supplier) throws IOException {
+ return toStringBuilder(supplier).toString();
+ }
+
+ /**
+ * Reads all characters from a {@link Readable} object into a new
+ * {@link StringBuilder} instance. Does not close the {@code Readable}.
+ *
+ * @param r the object to read from
+ * @return a {@link StringBuilder} containing all the characters
+ * @throws IOException if an I/O error occurs
+ */
+ private static StringBuilder toStringBuilder(Readable r) throws IOException {
+ StringBuilder sb = new StringBuilder();
+ copy(r, sb);
+ return sb;
+ }
+
+ /**
+ * Returns the characters from a {@link Readable} & {@link Closeable} object
+ * supplied by a factory as a new {@link StringBuilder} instance.
+ *
+ * @param supplier the factory to read from
+ * @throws IOException if an I/O error occurs
+ */
+ private static <R extends Readable & Closeable> StringBuilder toStringBuilder(
+ InputSupplier<R> supplier) throws IOException {
+ boolean threw = true;
+ R r = supplier.getInput();
+ try {
+ StringBuilder result = toStringBuilder(r);
+ threw = false;
+ return result;
+ } finally {
+ Closeables.close(r, threw);
+ }
+ }
+
+ /**
+ * Reads the first line from a {@link Readable} & {@link Closeable} object
+ * supplied by a factory. The line does not include line-termination
+ * characters, but does include other leading and trailing whitespace.
+ *
+ * @param supplier the factory to read from
+ * @return the first line, or null if the reader is empty
+ * @throws IOException if an I/O error occurs
+ */
+ public static <R extends Readable & Closeable> String readFirstLine(
+ InputSupplier<R> supplier) throws IOException {
+ boolean threw = true;
+ R r = supplier.getInput();
+ try {
+ String line = new LineReader(r).readLine();
+ threw = false;
+ return line;
+ } finally {
+ Closeables.close(r, threw);
+ }
+ }
+
+ /**
+ * Reads all of the lines from a {@link Readable} & {@link Closeable} object
+ * supplied by a factory. The lines do not include line-termination
+ * characters, but do include other leading and trailing whitespace.
+ *
+ * @param supplier the factory to read from
+ * @return a mutable {@link List} containing all the lines
+ * @throws IOException if an I/O error occurs
+ */
+ public static <R extends Readable & Closeable> List<String> readLines(
+ InputSupplier<R> supplier) throws IOException {
+ boolean threw = true;
+ R r = supplier.getInput();
+ try {
+ List<String> result = readLines(r);
+ threw = false;
+ return result;
+ } finally {
+ Closeables.close(r, threw);
+ }
+ }
+
+ /**
+ * Reads all of the lines from a {@link Readable} object. The lines do
+ * not include line-termination characters, but do include other
+ * leading and trailing whitespace.
+ *
+ * <p>Does not close the {@code Readable}. If reading files or resources you
+ * should use the {@link Files#readLines} and {@link Resources#readLines}
+ * methods.
+ *
+ * @param r the object to read from
+ * @return a mutable {@link List} containing all the lines
+ * @throws IOException if an I/O error occurs
+ */
+ public static List<String> readLines(Readable r) throws IOException {
+ List<String> result = new ArrayList<String>();
+ LineReader lineReader = new LineReader(r);
+ String line;
+ while ((line = lineReader.readLine()) != null) {
+ result.add(line);
+ }
+ return result;
+ }
+
+ /**
+ * Streams lines from a {@link Readable} and {@link Closeable} object
+ * supplied by a factory, stopping when our callback returns false, or we
+ * have read all of the lines.
+ *
+ * @param supplier the factory to read from
+ * @param callback the LineProcessor to use to handle the lines
+ * @return the output of processing the lines
+ * @throws IOException if an I/O error occurs
+ */
+ public static <R extends Readable & Closeable, T> T readLines(
+ InputSupplier<R> supplier, LineProcessor<T> callback) throws IOException {
+ boolean threw = true;
+ R r = supplier.getInput();
+ try {
+ LineReader lineReader = new LineReader(r);
+ String line;
+ while ((line = lineReader.readLine()) != null) {
+ if (!callback.processLine(line)) {
+ break;
+ }
+ }
+ threw = false;
+ } finally {
+ Closeables.close(r, threw);
+ }
+ return callback.getResult();
+ }
+
+ /**
+ * Joins multiple {@link Reader} suppliers into a single supplier.
+ * Reader returned from the supplier will contain the concatenated data
+ * from the readers of the underlying suppliers.
+ *
+ * <p>Reading from the joined reader will throw a {@link NullPointerException}
+ * if any of the suppliers are null or return null.
+ *
+ * <p>Only one underlying reader will be open at a time. Closing the
+ * joined reader will close the open underlying reader.
+ *
+ * @param suppliers the suppliers to concatenate
+ * @return a supplier that will return a reader containing the concatenated
+ * data
+ */
+ public static InputSupplier<Reader> join(
+ final Iterable<? extends InputSupplier<? extends Reader>> suppliers) {
+ return new InputSupplier<Reader>() {
+ @Override public Reader getInput() throws IOException {
+ return new MultiReader(suppliers.iterator());
+ }
+ };
+ }
+
+ /** Varargs form of {@link #join(Iterable)}. */
+ public static InputSupplier<Reader> join(
+ InputSupplier<? extends Reader>... suppliers) {
+ return join(Arrays.asList(suppliers));
+ }
+
+ /**
+ * Discards {@code n} characters of data from the reader. This method
+ * will block until the full amount has been skipped. Does not close the
+ * reader.
+ *
+ * @param reader the reader to read from
+ * @param n the number of characters to skip
+ * @throws EOFException if this stream reaches the end before skipping all
+ * the bytes
+ * @throws IOException if an I/O error occurs
+ */
+ public static void skipFully(Reader reader, long n) throws IOException {
+ while (n > 0) {
+ long amt = reader.skip(n);
+ if (amt == 0) {
+ // force a blocking read
+ if (reader.read() == -1) {
+ throw new EOFException();
+ }
+ n--;
+ } else {
+ n -= amt;
+ }
+ }
+ }
+
+ /**
+ * Returns a Writer that sends all output to the given {@link Appendable}
+ * target. Closing the writer will close the target if it is {@link
+ * Closeable}, and flushing the writer will flush the target if it is {@link
+ * java.io.Flushable}.
+ *
+ * @param target the object to which output will be sent
+ * @return a new Writer object, unless target is a Writer, in which case the
+ * target is returned
+ */
+ public static Writer asWriter(Appendable target) {
+ if (target instanceof Writer) {
+ return (Writer) target;
+ }
+ return new AppendableWriter(target);
+ }
+}
diff --git a/guava/src/com/google/common/io/Closeables.java b/guava/src/com/google/common/io/Closeables.java
new file mode 100644
index 0000000..e619887
--- /dev/null
+++ b/guava/src/com/google/common/io/Closeables.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2007 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 com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+
+import java.io.Closeable;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.annotation.Nullable;
+
+/**
+ * Utility methods for working with {@link Closeable} objects.
+ *
+ * @author Michael Lancaster
+ * @since 1.0
+ */
+@Beta
+public final class Closeables {
+ @VisibleForTesting static final Logger logger
+ = Logger.getLogger(Closeables.class.getName());
+
+ private Closeables() {}
+
+ /**
+ * Closes a {@link Closeable}, with control over whether an
+ * {@code IOException} may be thrown. This is primarily useful in a
+ * finally block, where a thrown exception needs to be logged but not
+ * propagated (otherwise the original exception will be lost).
+ *
+ * <p>If {@code swallowIOException} is true then we never throw
+ * {@code IOException} but merely log it.
+ *
+ * <p>Example:
+ *
+ * <p><pre>public void useStreamNicely() throws IOException {
+ * SomeStream stream = new SomeStream("foo");
+ * boolean threw = true;
+ * try {
+ * // Some code which does something with the Stream. May throw a
+ * // Throwable.
+ * threw = false; // No throwable thrown.
+ * } finally {
+ * // Close the stream.
+ * // If an exception occurs, only rethrow it if (threw==false).
+ * Closeables.close(stream, threw);
+ * }
+ * </pre>
+ *
+ * @param closeable the {@code Closeable} object to be closed, or null,
+ * in which case this method does nothing
+ * @param swallowIOException if true, don't propagate IO exceptions
+ * thrown by the {@code close} methods
+ * @throws IOException if {@code swallowIOException} is false and
+ * {@code close} throws an {@code IOException}.
+ */
+ public static void close(@Nullable Closeable closeable,
+ boolean swallowIOException) throws IOException {
+ if (closeable == null) {
+ return;
+ }
+ try {
+ closeable.close();
+ } catch (IOException e) {
+ if (swallowIOException) {
+ logger.log(Level.WARNING,
+ "IOException thrown while closing Closeable.", e);
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ /**
+ * Equivalent to calling {@code close(closeable, true)}, but with no
+ * IOException in the signature.
+ * @param closeable the {@code Closeable} object to be closed, or null, in
+ * which case this method does nothing
+ */
+ public static void closeQuietly(@Nullable Closeable closeable) {
+ try {
+ close(closeable, true);
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, "IOException should not have been thrown.", e);
+ }
+ }
+}
diff --git a/guava/src/com/google/common/io/CountingInputStream.java b/guava/src/com/google/common/io/CountingInputStream.java
new file mode 100644
index 0000000..d11c8ec
--- /dev/null
+++ b/guava/src/com/google/common/io/CountingInputStream.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2007 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 com.google.common.annotations.Beta;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * An {@link InputStream} that counts the number of bytes read.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+@Beta
+public final class CountingInputStream extends FilterInputStream {
+
+ private long count;
+ private long mark = -1;
+
+ /**
+ * Wraps another input stream, counting the number of bytes read.
+ *
+ * @param in the input stream to be wrapped
+ */
+ public CountingInputStream(InputStream in) {
+ super(in);
+ }
+
+ /** Returns the number of bytes read. */
+ public long getCount() {
+ return count;
+ }
+
+ @Override public int read() throws IOException {
+ int result = in.read();
+ if (result != -1) {
+ count++;
+ }
+ return result;
+ }
+
+ @Override public int read(byte[] b, int off, int len) throws IOException {
+ int result = in.read(b, off, len);
+ if (result != -1) {
+ count += result;
+ }
+ return result;
+ }
+
+ @Override public long skip(long n) throws IOException {
+ long result = in.skip(n);
+ count += result;
+ return result;
+ }
+
+ @Override public synchronized void mark(int readlimit) {
+ in.mark(readlimit);
+ mark = count;
+ // it's okay to mark even if mark isn't supported, as reset won't work
+ }
+
+ @Override public synchronized void reset() throws IOException {
+ if (!in.markSupported()) {
+ throw new IOException("Mark not supported");
+ }
+ if (mark == -1) {
+ throw new IOException("Mark not set");
+ }
+
+ in.reset();
+ count = mark;
+ }
+}
diff --git a/guava/src/com/google/common/io/CountingOutputStream.java b/guava/src/com/google/common/io/CountingOutputStream.java
new file mode 100644
index 0000000..5f57714
--- /dev/null
+++ b/guava/src/com/google/common/io/CountingOutputStream.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007 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 com.google.common.annotations.Beta;
+
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An OutputStream that counts the number of bytes written.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+@Beta
+public final class CountingOutputStream extends FilterOutputStream {
+
+ private long count;
+
+ /**
+ * Wraps another output stream, counting the number of bytes written.
+ *
+ * @param out the output stream to be wrapped
+ */
+ public CountingOutputStream(OutputStream out) {
+ super(out);
+ }
+
+ /** Returns the number of bytes written. */
+ public long getCount() {
+ return count;
+ }
+
+ @Override public void write(byte[] b, int off, int len) throws IOException {
+ out.write(b, off, len);
+ count += len;
+ }
+
+ @Override public void write(int b) throws IOException {
+ out.write(b);
+ count++;
+ }
+}
diff --git a/guava/src/com/google/common/io/FileBackedOutputStream.java b/guava/src/com/google/common/io/FileBackedOutputStream.java
new file mode 100644
index 0000000..ce593b2
--- /dev/null
+++ b/guava/src/com/google/common/io/FileBackedOutputStream.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2008 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 com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * An {@link OutputStream} that starts buffering to a byte array, but
+ * switches to file buffering once the data reaches a configurable size.
+ *
+ * <p>This class is thread-safe.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+@Beta
+public final class FileBackedOutputStream extends OutputStream {
+
+ private final int fileThreshold;
+ private final boolean resetOnFinalize;
+ private final InputSupplier<InputStream> supplier;
+
+ private OutputStream out;
+ private MemoryOutput memory;
+ private File file;
+
+ /** ByteArrayOutputStream that exposes its internals. */
+ private static class MemoryOutput extends ByteArrayOutputStream {
+ byte[] getBuffer() {
+ return buf;
+ }
+
+ int getCount() {
+ return count;
+ }
+ }
+
+ /** Returns the file holding the data (possibly null). */
+ @VisibleForTesting synchronized File getFile() {
+ return file;
+ }
+
+ /**
+ * Creates a new instance that uses the given file threshold, and does
+ * not reset the data when the {@link InputSupplier} returned by
+ * {@link #getSupplier} is finalized.
+ *
+ * @param fileThreshold the number of bytes before the stream should
+ * switch to buffering to a file
+ */
+ public FileBackedOutputStream(int fileThreshold) {
+ this(fileThreshold, false);
+ }
+
+ /**
+ * Creates a new instance that uses the given file threshold, and
+ * optionally resets the data when the {@link InputSupplier} returned
+ * by {@link #getSupplier} is finalized.
+ *
+ * @param fileThreshold the number of bytes before the stream should
+ * switch to buffering to a file
+ * @param resetOnFinalize if true, the {@link #reset} method will
+ * be called when the {@link InputSupplier} returned by {@link
+ * #getSupplier} is finalized
+ */
+ public FileBackedOutputStream(int fileThreshold, boolean resetOnFinalize) {
+ this.fileThreshold = fileThreshold;
+ this.resetOnFinalize = resetOnFinalize;
+ memory = new MemoryOutput();
+ out = memory;
+
+ if (resetOnFinalize) {
+ supplier = new InputSupplier<InputStream>() {
+ @Override
+ public InputStream getInput() throws IOException {
+ return openStream();
+ }
+
+ @Override protected void finalize() {
+ try {
+ reset();
+ } catch (Throwable t) {
+ t.printStackTrace(System.err);
+ }
+ }
+ };
+ } else {
+ supplier = new InputSupplier<InputStream>() {
+ @Override
+ public InputStream getInput() throws IOException {
+ return openStream();
+ }
+ };
+ }
+ }
+
+ /**
+ * Returns a supplier that may be used to retrieve the data buffered
+ * by this stream.
+ */
+ public InputSupplier<InputStream> getSupplier() {
+ return supplier;
+ }
+
+ private synchronized InputStream openStream() throws IOException {
+ if (file != null) {
+ return new FileInputStream(file);
+ } else {
+ return new ByteArrayInputStream(
+ memory.getBuffer(), 0, memory.getCount());
+ }
+ }
+
+ /**
+ * Calls {@link #close} if not already closed, and then resets this
+ * object back to its initial state, for reuse. If data was buffered
+ * to a file, it will be deleted.
+ *
+ * @throws IOException if an I/O error occurred while deleting the file buffer
+ */
+ public synchronized void reset() throws IOException {
+ try {
+ close();
+ } finally {
+ if (memory == null) {
+ memory = new MemoryOutput();
+ } else {
+ memory.reset();
+ }
+ out = memory;
+ if (file != null) {
+ File deleteMe = file;
+ file = null;
+ if (!deleteMe.delete()) {
+ throw new IOException("Could not delete: " + deleteMe);
+ }
+ }
+ }
+ }
+
+ @Override public synchronized void write(int b) throws IOException {
+ update(1);
+ out.write(b);
+ }
+
+ @Override public synchronized void write(byte[] b) throws IOException {
+ write(b, 0, b.length);
+ }
+
+ @Override public synchronized void write(byte[] b, int off, int len)
+ throws IOException {
+ update(len);
+ out.write(b, off, len);
+ }
+
+ @Override public synchronized void close() throws IOException {
+ out.close();
+ }
+
+ @Override public synchronized void flush() throws IOException {
+ out.flush();
+ }
+
+ /**
+ * Checks if writing {@code len} bytes would go over threshold, and
+ * switches to file buffering if so.
+ */
+ private void update(int len) throws IOException {
+ if (file == null && (memory.getCount() + len > fileThreshold)) {
+ File temp = File.createTempFile("FileBackedOutputStream", null);
+ if (resetOnFinalize) {
+ // Finalizers are not guaranteed to be called on system shutdown;
+ // this is insurance.
+ temp.deleteOnExit();
+ }
+ FileOutputStream transfer = new FileOutputStream(temp);
+ transfer.write(memory.getBuffer(), 0, memory.getCount());
+ transfer.flush();
+
+ // We've successfully transferred the data; switch to writing to file
+ out = transfer;
+ file = temp;
+ memory = null;
+ }
+ }
+}
diff --git a/guava/src/com/google/common/io/Files.java b/guava/src/com/google/common/io/Files.java
new file mode 100644
index 0000000..71b5dee
--- /dev/null
+++ b/guava/src/com/google/common/io/Files.java
@@ -0,0 +1,780 @@
+/*
+ * Copyright (C) 2007 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.checkNotNull;
+
+import com.google.common.annotations.Beta;
+import com.google.common.base.Charsets;
+import com.google.common.base.Joiner;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Splitter;
+import com.google.common.hash.HashCode;
+import com.google.common.hash.HashFunction;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.RandomAccessFile;
+import java.nio.MappedByteBuffer;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileChannel.MapMode;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.Checksum;
+
+/**
+ * Provides utility methods for working with files.
+ *
+ * <p>All method parameters must be non-null unless documented otherwise.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+@Beta
+public final class Files {
+
+ /** Maximum loop count when creating temp directories. */
+ private static final int TEMP_DIR_ATTEMPTS = 10000;
+
+ private Files() {}
+
+ /**
+ * Returns a buffered reader that reads from a file using the given
+ * character set.
+ *
+ * @param file the file to read from
+ * @param charset the charset used to decode the input stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @return the buffered reader
+ */
+ public static BufferedReader newReader(File file, Charset charset)
+ throws FileNotFoundException {
+ return new BufferedReader(
+ new InputStreamReader(new FileInputStream(file), charset));
+ }
+
+ /**
+ * Returns a buffered writer that writes to a file using the given
+ * character set.
+ *
+ * @param file the file to write to
+ * @param charset the charset used to encode the output stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @return the buffered writer
+ */
+ public static BufferedWriter newWriter(File file, Charset charset)
+ throws FileNotFoundException {
+ return new BufferedWriter(
+ new OutputStreamWriter(new FileOutputStream(file), charset));
+ }
+
+ /**
+ * Returns a factory that will supply instances of {@link FileInputStream}
+ * that read from a file.
+ *
+ * @param file the file to read from
+ * @return the factory
+ */
+ public static InputSupplier<FileInputStream> newInputStreamSupplier(
+ final File file) {
+ Preconditions.checkNotNull(file);
+ return new InputSupplier<FileInputStream>() {
+ @Override
+ public FileInputStream getInput() throws IOException {
+ return new FileInputStream(file);
+ }
+ };
+ }
+
+ /**
+ * Returns a factory that will supply instances of {@link FileOutputStream}
+ * that write to a file.
+ *
+ * @param file the file to write to
+ * @return the factory
+ */
+ public static OutputSupplier<FileOutputStream> newOutputStreamSupplier(
+ File file) {
+ return newOutputStreamSupplier(file, false);
+ }
+
+ /**
+ * Returns a factory that will supply instances of {@link FileOutputStream}
+ * that write to or append to a file.
+ *
+ * @param file the file to write to
+ * @param append if true, the encoded characters will be appended to the file;
+ * otherwise the file is overwritten
+ * @return the factory
+ */
+ public static OutputSupplier<FileOutputStream> newOutputStreamSupplier(
+ final File file, final boolean append) {
+ Preconditions.checkNotNull(file);
+ return new OutputSupplier<FileOutputStream>() {
+ @Override
+ public FileOutputStream getOutput() throws IOException {
+ return new FileOutputStream(file, append);
+ }
+ };
+ }
+
+ /**
+ * Returns a factory that will supply instances of
+ * {@link InputStreamReader} that read a file using the given character set.
+ *
+ * @param file the file to read from
+ * @param charset the charset used to decode the input stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @return the factory
+ */
+ public static InputSupplier<InputStreamReader> newReaderSupplier(File file,
+ Charset charset) {
+ return CharStreams.newReaderSupplier(newInputStreamSupplier(file), charset);
+ }
+
+ /**
+ * Returns a factory that will supply instances of {@link OutputStreamWriter}
+ * that write to a file using the given character set.
+ *
+ * @param file the file to write to
+ * @param charset the charset used to encode the output stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @return the factory
+ */
+ public static OutputSupplier<OutputStreamWriter> newWriterSupplier(File file,
+ Charset charset) {
+ return newWriterSupplier(file, charset, false);
+ }
+
+ /**
+ * Returns a factory that will supply instances of {@link OutputStreamWriter}
+ * that write to or append to a file using the given character set.
+ *
+ * @param file the file to write to
+ * @param charset the charset used to encode the output stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @param append if true, the encoded characters will be appended to the file;
+ * otherwise the file is overwritten
+ * @return the factory
+ */
+ public static OutputSupplier<OutputStreamWriter> newWriterSupplier(File file,
+ Charset charset, boolean append) {
+ return CharStreams.newWriterSupplier(newOutputStreamSupplier(file, append),
+ charset);
+ }
+
+ /**
+ * Reads all bytes from a file into a byte array.
+ *
+ * @param file the file to read from
+ * @return a byte array containing all the bytes from file
+ * @throws IllegalArgumentException if the file is bigger than the largest
+ * possible byte array (2^31 - 1)
+ * @throws IOException if an I/O error occurs
+ */
+ public static byte[] toByteArray(File file) throws IOException {
+ Preconditions.checkArgument(file.length() <= Integer.MAX_VALUE);
+ if (file.length() == 0) {
+ // Some special files are length 0 but have content nonetheless.
+ return ByteStreams.toByteArray(newInputStreamSupplier(file));
+ } else {
+ // Avoid an extra allocation and copy.
+ byte[] b = new byte[(int) file.length()];
+ boolean threw = true;
+ InputStream in = new FileInputStream(file);
+ try {
+ ByteStreams.readFully(in, b);
+ threw = false;
+ } finally {
+ Closeables.close(in, threw);
+ }
+ return b;
+ }
+ }
+
+ /**
+ * Reads all characters from a file into a {@link String}, using the given
+ * character set.
+ *
+ * @param file the file to read from
+ * @param charset the charset used to decode the input stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @return a string containing all the characters from the file
+ * @throws IOException if an I/O error occurs
+ */
+ public static String toString(File file, Charset charset) throws IOException {
+ return new String(toByteArray(file), charset.name());
+ }
+
+ /**
+ * Copies to a file all bytes from an {@link InputStream} supplied by a
+ * factory.
+ *
+ * @param from the input factory
+ * @param to the destination file
+ * @throws IOException if an I/O error occurs
+ */
+ public static void copy(InputSupplier<? extends InputStream> from, File to)
+ throws IOException {
+ ByteStreams.copy(from, newOutputStreamSupplier(to));
+ }
+
+ /**
+ * Overwrites a file with the contents of a byte array.
+ *
+ * @param from the bytes to write
+ * @param to the destination file
+ * @throws IOException if an I/O error occurs
+ */
+ public static void write(byte[] from, File to) throws IOException {
+ ByteStreams.write(from, newOutputStreamSupplier(to));
+ }
+
+ /**
+ * Copies all bytes from a file to an {@link OutputStream} supplied by
+ * a factory.
+ *
+ * @param from the source file
+ * @param to the output factory
+ * @throws IOException if an I/O error occurs
+ */
+ public static void copy(File from, OutputSupplier<? extends OutputStream> to)
+ throws IOException {
+ ByteStreams.copy(newInputStreamSupplier(from), to);
+ }
+
+ /**
+ * Copies all bytes from a file to an output stream.
+ *
+ * @param from the source file
+ * @param to the output stream
+ * @throws IOException if an I/O error occurs
+ */
+ public static void copy(File from, OutputStream to) throws IOException {
+ ByteStreams.copy(newInputStreamSupplier(from), to);
+ }
+
+ /**
+ * Copies all the bytes from one file to another.
+ *.
+ * @param from the source file
+ * @param to the destination file
+ * @throws IOException if an I/O error occurs
+ * @throws IllegalArgumentException if {@code from.equals(to)}
+ */
+ public static void copy(File from, File to) throws IOException {
+ Preconditions.checkArgument(!from.equals(to),
+ "Source %s and destination %s must be different", from, to);
+ copy(newInputStreamSupplier(from), to);
+ }
+
+ /**
+ * Copies to a file all characters from a {@link Readable} and
+ * {@link Closeable} object supplied by a factory, using the given
+ * character set.
+ *
+ * @param from the readable supplier
+ * @param to the destination file
+ * @param charset the charset used to encode the output stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @throws IOException if an I/O error occurs
+ */
+ public static <R extends Readable & Closeable> void copy(
+ InputSupplier<R> from, File to, Charset charset) throws IOException {
+ CharStreams.copy(from, newWriterSupplier(to, charset));
+ }
+
+ /**
+ * Writes a character sequence (such as a string) to a file using the given
+ * character set.
+ *
+ * @param from the character sequence to write
+ * @param to the destination file
+ * @param charset the charset used to encode the output stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @throws IOException if an I/O error occurs
+ */
+ public static void write(CharSequence from, File to, Charset charset)
+ throws IOException {
+ write(from, to, charset, false);
+ }
+
+ /**
+ * Appends a character sequence (such as a string) to a file using the given
+ * character set.
+ *
+ * @param from the character sequence to append
+ * @param to the destination file
+ * @param charset the charset used to encode the output stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @throws IOException if an I/O error occurs
+ */
+ public static void append(CharSequence from, File to, Charset charset)
+ throws IOException {
+ write(from, to, charset, true);
+ }
+
+ /**
+ * Private helper method. Writes a character sequence to a file,
+ * optionally appending.
+ *
+ * @param from the character sequence to append
+ * @param to the destination file
+ * @param charset the charset used to encode the output stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @param append true to append, false to overwrite
+ * @throws IOException if an I/O error occurs
+ */
+ private static void write(CharSequence from, File to, Charset charset,
+ boolean append) throws IOException {
+ CharStreams.write(from, newWriterSupplier(to, charset, append));
+ }
+
+ /**
+ * Copies all characters from a file to a {@link Appendable} &
+ * {@link Closeable} object supplied by a factory, using the given
+ * character set.
+ *
+ * @param from the source file
+ * @param charset the charset used to decode the input stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @param to the appendable supplier
+ * @throws IOException if an I/O error occurs
+ */
+ public static <W extends Appendable & Closeable> void copy(File from,
+ Charset charset, OutputSupplier<W> to) throws IOException {
+ CharStreams.copy(newReaderSupplier(from, charset), to);
+ }
+
+ /**
+ * Copies all characters from a file to an appendable object,
+ * using the given character set.
+ *
+ * @param from the source file
+ * @param charset the charset used to decode the input stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @param to the appendable object
+ * @throws IOException if an I/O error occurs
+ */
+ public static void copy(File from, Charset charset, Appendable to)
+ throws IOException {
+ CharStreams.copy(newReaderSupplier(from, charset), to);
+ }
+
+ /**
+ * Returns true if the files contains the same bytes.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ public static boolean equal(File file1, File file2) throws IOException {
+ if (file1 == file2 || file1.equals(file2)) {
+ return true;
+ }
+
+ /*
+ * Some operating systems may return zero as the length for files
+ * denoting system-dependent entities such as devices or pipes, in
+ * which case we must fall back on comparing the bytes directly.
+ */
+ long len1 = file1.length();
+ long len2 = file2.length();
+ if (len1 != 0 && len2 != 0 && len1 != len2) {
+ return false;
+ }
+ return ByteStreams.equal(newInputStreamSupplier(file1),
+ newInputStreamSupplier(file2));
+ }
+
+ /**
+ * Atomically creates a new directory somewhere beneath the system's
+ * temporary directory (as defined by the {@code java.io.tmpdir} system
+ * property), and returns its name.
+ *
+ * <p>Use this method instead of {@link File#createTempFile(String, String)}
+ * when you wish to create a directory, not a regular file. A common pitfall
+ * is to call {@code createTempFile}, delete the file and create a
+ * directory in its place, but this leads a race condition which can be
+ * exploited to create security vulnerabilities, especially when executable
+ * files are to be written into the directory.
+ *
+ * <p>This method assumes that the temporary volume is writable, has free
+ * inodes and free blocks, and that it will not be called thousands of times
+ * per second.
+ *
+ * @return the newly-created directory
+ * @throws IllegalStateException if the directory could not be created
+ */
+ public static File createTempDir() {
+ File baseDir = new File(System.getProperty("java.io.tmpdir"));
+ String baseName = System.currentTimeMillis() + "-";
+
+ for (int counter = 0; counter < TEMP_DIR_ATTEMPTS; counter++) {
+ File tempDir = new File(baseDir, baseName + counter);
+ if (tempDir.mkdir()) {
+ return tempDir;
+ }
+ }
+ throw new IllegalStateException("Failed to create directory within "
+ + TEMP_DIR_ATTEMPTS + " attempts (tried "
+ + baseName + "0 to " + baseName + (TEMP_DIR_ATTEMPTS - 1) + ')');
+ }
+
+ /**
+ * Creates an empty file or updates the last updated timestamp on the
+ * same as the unix command of the same name.
+ *
+ * @param file the file to create or update
+ * @throws IOException if an I/O error occurs
+ */
+ public static void touch(File file) throws IOException {
+ if (!file.createNewFile()
+ && !file.setLastModified(System.currentTimeMillis())) {
+ throw new IOException("Unable to update modification time of " + file);
+ }
+ }
+
+ /**
+ * Creates any necessary but nonexistent parent directories of the specified
+ * file. Note that if this operation fails it may have succeeded in creating
+ * some (but not all) of the necessary parent directories.
+ *
+ * @throws IOException if an I/O error occurs, or if any necessary but
+ * nonexistent parent directories of the specified file could not be
+ * created.
+ * @since 4.0
+ */
+ public static void createParentDirs(File file) throws IOException {
+ File parent = file.getCanonicalFile().getParentFile();
+ if (parent == null) {
+ /*
+ * The given directory is a filesystem root. All zero of its ancestors
+ * exist. This doesn't mean that the root itself exists -- consider x:\ on
+ * a Windows machine without such a drive -- or even that the caller can
+ * create it, but this method makes no such guarantees even for non-root
+ * files.
+ */
+ return;
+ }
+ parent.mkdirs();
+ if (!parent.isDirectory()) {
+ throw new IOException("Unable to create parent directories of " + file);
+ }
+ }
+
+ /**
+ * Moves the file from one path to another. This method can rename a file or
+ * move it to a different directory, like the Unix {@code mv} command.
+ *
+ * @param from the source file
+ * @param to the destination file
+ * @throws IOException if an I/O error occurs
+ * @throws IllegalArgumentException if {@code from.equals(to)}
+ */
+ public static void move(File from, File to) throws IOException {
+ Preconditions.checkNotNull(to);
+ Preconditions.checkArgument(!from.equals(to),
+ "Source %s and destination %s must be different", from, to);
+
+ if (!from.renameTo(to)) {
+ copy(from, to);
+ if (!from.delete()) {
+ if (!to.delete()) {
+ throw new IOException("Unable to delete " + to);
+ }
+ throw new IOException("Unable to delete " + from);
+ }
+ }
+ }
+
+ /**
+ * Reads the first line from a file. The line does not include
+ * line-termination characters, but does include other leading and
+ * trailing whitespace.
+ *
+ * @param file the file to read from
+ * @param charset the charset used to decode the input stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @return the first line, or null if the file is empty
+ * @throws IOException if an I/O error occurs
+ */
+ public static String readFirstLine(File file, Charset charset)
+ throws IOException {
+ return CharStreams.readFirstLine(Files.newReaderSupplier(file, charset));
+ }
+
+ /**
+ * Reads all of the lines from a file. The lines do not include
+ * line-termination characters, but do include other leading and
+ * trailing whitespace.
+ *
+ * @param file the file to read from
+ * @param charset the charset used to decode the input stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @return a mutable {@link List} containing all the lines
+ * @throws IOException if an I/O error occurs
+ */
+ public static List<String> readLines(File file, Charset charset)
+ throws IOException {
+ return CharStreams.readLines(Files.newReaderSupplier(file, charset));
+ }
+
+ /**
+ * Streams lines from a {@link File}, stopping when our callback returns
+ * false, or we have read all of the lines.
+ *
+ * @param file the file to read from
+ * @param charset the charset used to decode the input stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @param callback the {@link LineProcessor} to use to handle the lines
+ * @return the output of processing the lines
+ * @throws IOException if an I/O error occurs
+ */
+ public static <T> T readLines(File file, Charset charset,
+ LineProcessor<T> callback) throws IOException {
+ return CharStreams.readLines(Files.newReaderSupplier(file, charset),
+ callback);
+ }
+
+ /**
+ * Process the bytes of a file.
+ *
+ * <p>(If this seems too complicated, maybe you're looking for
+ * {@link #toByteArray}.)
+ *
+ * @param file the file to read
+ * @param processor the object to which the bytes of the file are passed.
+ * @return the result of the byte processor
+ * @throws IOException if an I/O error occurs
+ */
+ public static <T> T readBytes(File file, ByteProcessor<T> processor)
+ throws IOException {
+ return ByteStreams.readBytes(newInputStreamSupplier(file), processor);
+ }
+
+ /**
+ * Computes and returns the checksum value for a file.
+ * The checksum object is reset when this method returns successfully.
+ *
+ * @param file the file to read
+ * @param checksum the checksum object
+ * @return the result of {@link Checksum#getValue} after updating the
+ * checksum object with all of the bytes in the file
+ * @throws IOException if an I/O error occurs
+ */
+ public static long getChecksum(File file, Checksum checksum)
+ throws IOException {
+ return ByteStreams.getChecksum(newInputStreamSupplier(file), checksum);
+ }
+
+ /**
+ * Computes the hash code of the {@code file} using {@code hashFunction}.
+ *
+ * @param file the file to read
+ * @param hashFunction the hash function to use to hash the data
+ * @return the {@link HashCode} of all of the bytes in the file
+ * @throws IOException if an I/O error occurs
+ * @since 12.0
+ */
+ public static HashCode hash(File file, HashFunction hashFunction)
+ throws IOException {
+ return ByteStreams.hash(newInputStreamSupplier(file), hashFunction);
+ }
+
+ /**
+ * Fully maps a file read-only in to memory as per
+ * {@link FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)}.
+ *
+ * <p>Files are mapped from offset 0 to its length.
+ *
+ * <p>This only works for files <= {@link Integer#MAX_VALUE} bytes.
+ *
+ * @param file the file to map
+ * @return a read-only buffer reflecting {@code file}
+ * @throws FileNotFoundException if the {@code file} does not exist
+ * @throws IOException if an I/O error occurs
+ *
+ * @see FileChannel#map(MapMode, long, long)
+ * @since 2.0
+ */
+ public static MappedByteBuffer map(File file) throws IOException {
+ return map(file, MapMode.READ_ONLY);
+ }
+
+ /**
+ * Fully maps a file in to memory as per
+ * {@link FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)}
+ * using the requested {@link MapMode}.
+ *
+ * <p>Files are mapped from offset 0 to its length.
+ *
+ * <p>This only works for files <= {@link Integer#MAX_VALUE} bytes.
+ *
+ * @param file the file to map
+ * @param mode the mode to use when mapping {@code file}
+ * @return a buffer reflecting {@code file}
+ * @throws FileNotFoundException if the {@code file} does not exist
+ * @throws IOException if an I/O error occurs
+ *
+ * @see FileChannel#map(MapMode, long, long)
+ * @since 2.0
+ */
+ public static MappedByteBuffer map(File file, MapMode mode)
+ throws IOException {
+ if (!file.exists()) {
+ throw new FileNotFoundException(file.toString());
+ }
+ return map(file, mode, file.length());
+ }
+
+ /**
+ * Maps a file in to memory as per
+ * {@link FileChannel#map(java.nio.channels.FileChannel.MapMode, long, long)}
+ * using the requested {@link MapMode}.
+ *
+ * <p>Files are mapped from offset 0 to {@code size}.
+ *
+ * <p>If the mode is {@link MapMode#READ_WRITE} and the file does not exist,
+ * it will be created with the requested {@code size}. Thus this method is
+ * useful for creating memory mapped files which do not yet exist.
+ *
+ * <p>This only works for files <= {@link Integer#MAX_VALUE} bytes.
+ *
+ * @param file the file to map
+ * @param mode the mode to use when mapping {@code file}
+ * @return a buffer reflecting {@code file}
+ * @throws IOException if an I/O error occurs
+ *
+ * @see FileChannel#map(MapMode, long, long)
+ * @since 2.0
+ */
+ public static MappedByteBuffer map(File file, MapMode mode, long size)
+ throws FileNotFoundException, IOException {
+ RandomAccessFile raf =
+ new RandomAccessFile(file, mode == MapMode.READ_ONLY ? "r" : "rw");
+
+ boolean threw = true;
+ try {
+ MappedByteBuffer mbb = map(raf, mode, size);
+ threw = false;
+ return mbb;
+ } finally {
+ Closeables.close(raf, threw);
+ }
+ }
+
+ private static MappedByteBuffer map(RandomAccessFile raf, MapMode mode,
+ long size) throws IOException {
+ FileChannel channel = raf.getChannel();
+
+ boolean threw = true;
+ try {
+ MappedByteBuffer mbb = channel.map(mode, 0, size);
+ threw = false;
+ return mbb;
+ } finally {
+ Closeables.close(channel, threw);
+ }
+ }
+
+ /**
+ * Returns the lexically cleaned form of the path name, <i>usually</i> (but
+ * not always) equivalent to the original. The following heuristics are used:
+ *
+ * <ul>
+ * <li>empty string becomes .
+ * <li>. stays as .
+ * <li>fold out ./
+ * <li>fold out ../ when possible
+ * <li>collapse multiple slashes
+ * <li>delete trailing slashes (unless the path is just "/")
+ * </ul>
+ *
+ * These heuristics do not always match the behavior of the filesystem. In
+ * particular, consider the path {@code a/../b}, which {@code simplifyPath}
+ * will change to {@code b}. If {@code a} is a symlink to {@code x}, {@code
+ * a/../b} may refer to a sibling of {@code x}, rather than the sibling of
+ * {@code a} referred to by {@code b}.
+ *
+ * @since 11.0
+ */
+ public static String simplifyPath(String pathname) {
+ if (pathname.length() == 0) {
+ return ".";
+ }
+
+ // split the path apart
+ Iterable<String> components =
+ Splitter.on('/').omitEmptyStrings().split(pathname);
+ List<String> path = new ArrayList<String>();
+
+ // resolve ., .., and //
+ for (String component : components) {
+ if (component.equals(".")) {
+ continue;
+ } else if (component.equals("..")) {
+ if (path.size() > 0 && !path.get(path.size() - 1).equals("..")) {
+ path.remove(path.size() - 1);
+ } else {
+ path.add("..");
+ }
+ } else {
+ path.add(component);
+ }
+ }
+
+ // put it back together
+ String result = Joiner.on('/').join(path);
+ if (pathname.charAt(0) == '/') {
+ result = "/" + result;
+ }
+
+ while (result.startsWith("/../")) {
+ result = result.substring(3);
+ }
+ if (result.equals("/..")) {
+ result = "/";
+ } else if ("".equals(result)) {
+ result = ".";
+ }
+
+ return result;
+ }
+
+ /**
+ * Returns the <a href="http://en.wikipedia.org/wiki/Filename_extension">file
+ * extension</a> for the given file name, or the empty string if the file has
+ * no extension. The result does not include the '{@code .}'.
+ *
+ * @since 11.0
+ */
+ public static String getFileExtension(String fileName) {
+ checkNotNull(fileName);
+ int dotIndex = fileName.lastIndexOf('.');
+ return (dotIndex == -1) ? "" : fileName.substring(dotIndex + 1);
+ }
+}
diff --git a/guava/src/com/google/common/io/Flushables.java b/guava/src/com/google/common/io/Flushables.java
new file mode 100644
index 0000000..68ff860
--- /dev/null
+++ b/guava/src/com/google/common/io/Flushables.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 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 com.google.common.annotations.Beta;
+
+import java.io.Flushable;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * Utility methods for working with {@link Flushable} objects.
+ *
+ * @author Michael Lancaster
+ * @since 1.0
+ */
+@Beta
+public final class Flushables {
+ private static final Logger logger
+ = Logger.getLogger(Flushables.class.getName());
+
+ private Flushables() {}
+
+ /**
+ * Flush a {@link Flushable}, with control over whether an
+ * {@code IOException} may be thrown.
+ *
+ * <p>If {@code swallowIOException} is true, then we don't rethrow
+ * {@code IOException}, but merely log it.
+ *
+ * @param flushable the {@code Flushable} object to be flushed.
+ * @param swallowIOException if true, don't propagate IO exceptions
+ * thrown by the {@code flush} method
+ * @throws IOException if {@code swallowIOException} is false and
+ * {@link Flushable#flush} throws an {@code IOException}.
+ * @see Closeables#close
+ */
+ public static void flush(Flushable flushable, boolean swallowIOException)
+ throws IOException {
+ try {
+ flushable.flush();
+ } catch (IOException e) {
+ if (swallowIOException) {
+ logger.log(Level.WARNING,
+ "IOException thrown while flushing Flushable.", e);
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ /**
+ * Equivalent to calling {@code flush(flushable, true)}, but with no
+ * {@code IOException} in the signature.
+ *
+ * @param flushable the {@code Flushable} object to be flushed.
+ */
+ public static void flushQuietly(Flushable flushable) {
+ try {
+ flush(flushable, true);
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, "IOException should not have been thrown.", e);
+ }
+ }
+}
diff --git a/guava/src/com/google/common/io/InputSupplier.java b/guava/src/com/google/common/io/InputSupplier.java
new file mode 100644
index 0000000..2b6a4ad
--- /dev/null
+++ b/guava/src/com/google/common/io/InputSupplier.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2007 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 java.io.IOException;
+
+/**
+ * A factory for readable streams of bytes or characters.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+public interface InputSupplier<T> {
+
+ /**
+ * Returns an object that encapsulates a readable resource.
+ * <p>
+ * Like {@link Iterable#iterator}, this method may be called repeatedly to
+ * get independent channels to the same underlying resource.
+ * <p>
+ * Where the channel maintains a position within the resource, moving that
+ * cursor within one channel should not affect the starting position of
+ * channels returned by other calls.
+ */
+ T getInput() throws IOException;
+}
diff --git a/guava/src/com/google/common/io/LimitInputStream.java b/guava/src/com/google/common/io/LimitInputStream.java
new file mode 100644
index 0000000..e9d963d
--- /dev/null
+++ b/guava/src/com/google/common/io/LimitInputStream.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2007 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 com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * An InputStream that limits the number of bytes which can be read.
+ *
+ * @author Charles Fry
+ * @since 1.0
+ */
+@Beta
+public final class LimitInputStream extends FilterInputStream {
+
+ private long left;
+ private long mark = -1;
+
+ /**
+ * Wraps another input stream, limiting the number of bytes which can be read.
+ *
+ * @param in the input stream to be wrapped
+ * @param limit the maximum number of bytes to be read
+ */
+ public LimitInputStream(InputStream in, long limit) {
+ super(in);
+ Preconditions.checkNotNull(in);
+ Preconditions.checkArgument(limit >= 0, "limit must be non-negative");
+ left = limit;
+ }
+
+ @Override public int available() throws IOException {
+ return (int) Math.min(in.available(), left);
+ }
+
+ @Override public synchronized void mark(int readlimit) {
+ in.mark(readlimit);
+ mark = left;
+ // it's okay to mark even if mark isn't supported, as reset won't work
+ }
+
+ @Override public int read() throws IOException {
+ if (left == 0) {
+ return -1;
+ }
+
+ int result = in.read();
+ if (result != -1) {
+ --left;
+ }
+ return result;
+ }
+
+ @Override public int read(byte[] b, int off, int len) throws IOException {
+ if (left == 0) {
+ return -1;
+ }
+
+ len = (int) Math.min(len, left);
+ int result = in.read(b, off, len);
+ if (result != -1) {
+ left -= result;
+ }
+ return result;
+ }
+
+ @Override public synchronized void reset() throws IOException {
+ if (!in.markSupported()) {
+ throw new IOException("Mark not supported");
+ }
+ if (mark == -1) {
+ throw new IOException("Mark not set");
+ }
+
+ in.reset();
+ left = mark;
+ }
+
+ @Override public long skip(long n) throws IOException {
+ n = Math.min(n, left);
+ long skipped = in.skip(n);
+ left -= skipped;
+ return skipped;
+ }
+}
diff --git a/guava/src/com/google/common/io/LineBuffer.java b/guava/src/com/google/common/io/LineBuffer.java
new file mode 100644
index 0000000..1f1c8dc
--- /dev/null
+++ b/guava/src/com/google/common/io/LineBuffer.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2007 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 java.io.IOException;
+
+/**
+ * Package-protected abstract class that implements the line reading
+ * algorithm used by {@link LineReader}. Line separators are per {@link
+ * java.io.BufferedReader}: line feed, carriage return, or carriage
+ * return followed immediately by a linefeed.
+ *
+ * <p>Subclasses must implement {@link #handleLine}, call {@link #add}
+ * to pass character data, and call {@link #finish} at the end of stream.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+abstract class LineBuffer {
+ /** Holds partial line contents. */
+ private StringBuilder line = new StringBuilder();
+ /** Whether a line ending with a CR is pending processing. */
+ private boolean sawReturn;
+
+ /**
+ * Process additional characters from the stream. When a line separator
+ * is found the contents of the line and the line separator itself
+ * are passed to the abstract {@link #handleLine} method.
+ *
+ * @param cbuf the character buffer to process
+ * @param off the offset into the buffer
+ * @param len the number of characters to process
+ * @throws IOException if an I/O error occurs
+ * @see #finish
+ */
+ protected void add(char[] cbuf, int off, int len) throws IOException {
+ int pos = off;
+ if (sawReturn && len > 0) {
+ // Last call to add ended with a CR; we can handle the line now.
+ if (finishLine(cbuf[pos] == '\n')) {
+ pos++;
+ }
+ }
+
+ int start = pos;
+ for (int end = off + len; pos < end; pos++) {
+ switch (cbuf[pos]) {
+ case '\r':
+ line.append(cbuf, start, pos - start);
+ sawReturn = true;
+ if (pos + 1 < end) {
+ if (finishLine(cbuf[pos + 1] == '\n')) {
+ pos++;
+ }
+ }
+ start = pos + 1;
+ break;
+
+ case '\n':
+ line.append(cbuf, start, pos - start);
+ finishLine(true);
+ start = pos + 1;
+ break;
+ }
+ }
+ line.append(cbuf, start, off + len - start);
+ }
+
+ /** Called when a line is complete. */
+ private boolean finishLine(boolean sawNewline) throws IOException {
+ handleLine(line.toString(), sawReturn
+ ? (sawNewline ? "\r\n" : "\r")
+ : (sawNewline ? "\n" : ""));
+ line = new StringBuilder();
+ sawReturn = false;
+ return sawNewline;
+ }
+
+ /**
+ * Subclasses must call this method after finishing character processing,
+ * in order to ensure that any unterminated line in the buffer is
+ * passed to {@link #handleLine}.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ protected void finish() throws IOException {
+ if (sawReturn || line.length() > 0) {
+ finishLine(false);
+ }
+ }
+
+ /**
+ * Called for each line found in the character data passed to
+ * {@link #add}.
+ *
+ * @param line a line of text (possibly empty), without any line separators
+ * @param end the line separator; one of {@code "\r"}, {@code "\n"},
+ * {@code "\r\n"}, or {@code ""}
+ * @throws IOException if an I/O error occurs
+ */
+ protected abstract void handleLine(String line, String end)
+ throws IOException;
+}
diff --git a/guava/src/com/google/common/io/LineProcessor.java b/guava/src/com/google/common/io/LineProcessor.java
new file mode 100644
index 0000000..9ee6a0f
--- /dev/null
+++ b/guava/src/com/google/common/io/LineProcessor.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2009 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 com.google.common.annotations.Beta;
+
+import java.io.IOException;
+
+/**
+ * A callback to be used with the streaming {@code readLines} methods.
+ *
+ * <p>{@link #processLine} will be called for each line that is read, and
+ * should return {@code false} when you want to stop processing.
+ *
+ * @author Miles Barr
+ * @since 1.0
+ */
+@Beta
+public interface LineProcessor<T> {
+
+ /**
+ * This method will be called once for each line.
+ *
+ * @param line the line read from the input, without delimiter
+ * @return true to continue processing, false to stop
+ */
+ boolean processLine(String line) throws IOException;
+
+ /** Return the result of processing all the lines. */
+ T getResult();
+}
diff --git a/guava/src/com/google/common/io/LineReader.java b/guava/src/com/google/common/io/LineReader.java
new file mode 100644
index 0000000..69ae0cf
--- /dev/null
+++ b/guava/src/com/google/common/io/LineReader.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007 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 com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.nio.CharBuffer;
+import java.util.LinkedList;
+import java.util.Queue;
+
+/**
+ * A class for reading lines of text. Provides the same functionality
+ * as {@link java.io.BufferedReader#readLine()} but for all {@link Readable}
+ * objects, not just instances of {@link Reader}.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+@Beta
+public final class LineReader {
+ private final Readable readable;
+ private final Reader reader;
+ private final char[] buf = new char[0x1000]; // 4K
+ private final CharBuffer cbuf = CharBuffer.wrap(buf);
+
+ private final Queue<String> lines = new LinkedList<String>();
+ private final LineBuffer lineBuf = new LineBuffer() {
+ @Override protected void handleLine(String line, String end) {
+ lines.add(line);
+ }
+ };
+
+ /**
+ * Creates a new instance that will read lines from the given
+ * {@code Readable} object.
+ */
+ public LineReader(Readable readable) {
+ Preconditions.checkNotNull(readable);
+ this.readable = readable;
+ this.reader = (readable instanceof Reader) ? (Reader) readable : null;
+ }
+
+ /**
+ * Reads a line of text. A line is considered to be terminated by any
+ * one of a line feed ({@code '\n'}), a carriage return
+ * ({@code '\r'}), or a carriage return followed immediately by a linefeed
+ * ({@code "\r\n"}).
+ *
+ * @return a {@code String} containing the contents of the line, not
+ * including any line-termination characters, or {@code null} if the
+ * end of the stream has been reached.
+ * @throws IOException if an I/O error occurs
+ */
+ public String readLine() throws IOException {
+ while (lines.peek() == null) {
+ cbuf.clear();
+ // The default implementation of Reader#read(CharBuffer) allocates a
+ // temporary char[], so we call Reader#read(char[], int, int) instead.
+ int read = (reader != null)
+ ? reader.read(buf, 0, buf.length)
+ : readable.read(cbuf);
+ if (read == -1) {
+ lineBuf.finish();
+ break;
+ }
+ lineBuf.add(buf, 0, read);
+ }
+ return lines.poll();
+ }
+}
diff --git a/guava/src/com/google/common/io/LittleEndianDataInputStream.java b/guava/src/com/google/common/io/LittleEndianDataInputStream.java
new file mode 100644
index 0000000..e60d22f
--- /dev/null
+++ b/guava/src/com/google/common/io/LittleEndianDataInputStream.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2007 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 com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.Ints;
+import com.google.common.primitives.Longs;
+
+import java.io.DataInput;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.FilterInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * An implementation of {@link DataInput} that uses little-endian byte ordering
+ * for reading {@code short}, {@code int}, {@code float}, {@code double}, and
+ * {@code long} values.
+ * <p>
+ * <b>Note:</b> This class intentionally violates the specification of its
+ * supertype {@code DataInput}, which explicitly requires big-endian byte order.
+ *
+ * @author Chris Nokleberg
+ * @author Keith Bottner
+ * @since 8.0
+ */
+@Beta
+public final class LittleEndianDataInputStream extends FilterInputStream
+ implements DataInput {
+
+ /**
+ * Creates a {@code LittleEndianDataInputStream} that wraps the given stream.
+ *
+ * @param in the stream to delegate to
+ */
+ public LittleEndianDataInputStream(InputStream in) {
+ super(Preconditions.checkNotNull(in));
+ }
+
+ /**
+ * This method will throw an {@link UnsupportedOperationException}.
+ */
+ @Override
+ public String readLine() {
+ throw new UnsupportedOperationException("readLine is not supported");
+ }
+
+ @Override
+ public void readFully(byte[] b) throws IOException {
+ ByteStreams.readFully(this, b);
+ }
+
+ @Override
+ public void readFully(byte[] b, int off, int len) throws IOException {
+ ByteStreams.readFully(this, b, off, len);
+ }
+
+ @Override
+ public int skipBytes(int n) throws IOException {
+ return (int) in.skip(n);
+ }
+
+ @Override
+ public int readUnsignedByte() throws IOException {
+ int b1 = in.read();
+ if (0 > b1) {
+ throw new EOFException();
+ }
+
+ return b1;
+ }
+
+ /**
+ * Reads an unsigned {@code short} as specified by
+ * {@link DataInputStream#readUnsignedShort()}, except using little-endian
+ * byte order.
+ *
+ * @return the next two bytes of the input stream, interpreted as an
+ * unsigned 16-bit integer in little-endian byte order
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public int readUnsignedShort() throws IOException {
+ byte b1 = readAndCheckByte();
+ byte b2 = readAndCheckByte();
+
+ return Ints.fromBytes((byte) 0, (byte) 0, b2, b1);
+ }
+
+ /**
+ * Reads an integer as specified by {@link DataInputStream#readInt()}, except
+ * using little-endian byte order.
+ *
+ * @return the next four bytes of the input stream, interpreted as an
+ * {@code int} in little-endian byte order
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public int readInt() throws IOException {
+ byte b1 = readAndCheckByte();
+ byte b2 = readAndCheckByte();
+ byte b3 = readAndCheckByte();
+ byte b4 = readAndCheckByte();
+
+ return Ints.fromBytes( b4, b3, b2, b1);
+ }
+
+ /**
+ * Reads a {@code long} as specified by {@link DataInputStream#readLong()},
+ * except using little-endian byte order.
+ *
+ * @return the next eight bytes of the input stream, interpreted as a
+ * {@code long} in little-endian byte order
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public long readLong() throws IOException {
+ byte b1 = readAndCheckByte();
+ byte b2 = readAndCheckByte();
+ byte b3 = readAndCheckByte();
+ byte b4 = readAndCheckByte();
+ byte b5 = readAndCheckByte();
+ byte b6 = readAndCheckByte();
+ byte b7 = readAndCheckByte();
+ byte b8 = readAndCheckByte();
+
+ return Longs.fromBytes(b8, b7, b6, b5, b4, b3, b2, b1);
+ }
+
+ /**
+ * Reads a {@code float} as specified by {@link DataInputStream#readFloat()},
+ * except using little-endian byte order.
+ *
+ * @return the next four bytes of the input stream, interpreted as a
+ * {@code float} in little-endian byte order
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public float readFloat() throws IOException {
+ return Float.intBitsToFloat(readInt());
+ }
+
+ /**
+ * Reads a {@code double} as specified by
+ * {@link DataInputStream#readDouble()}, except using little-endian byte
+ * order.
+ *
+ * @return the next eight bytes of the input stream, interpreted as a
+ * {@code double} in little-endian byte order
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public double readDouble() throws IOException {
+ return Double.longBitsToDouble(readLong());
+ }
+
+ @Override
+ public String readUTF() throws IOException {
+ return new DataInputStream(in).readUTF();
+ }
+
+ /**
+ * Reads a {@code short} as specified by {@link DataInputStream#readShort()},
+ * except using little-endian byte order.
+ *
+ * @return the next two bytes of the input stream, interpreted as a
+ * {@code short} in little-endian byte order.
+ * @throws IOException if an I/O error occurs.
+ */
+ @Override
+ public short readShort() throws IOException {
+ return (short) readUnsignedShort();
+ }
+
+ /**
+ * Reads a char as specified by {@link DataInputStream#readChar()}, except
+ * using little-endian byte order.
+ *
+ * @return the next two bytes of the input stream, interpreted as a
+ * {@code char} in little-endian byte order
+ * @throws IOException if an I/O error occurs
+ */
+ @Override
+ public char readChar() throws IOException {
+ return (char) readUnsignedShort();
+ }
+
+ @Override
+ public byte readByte() throws IOException {
+ return (byte) readUnsignedByte();
+ }
+
+ @Override
+ public boolean readBoolean() throws IOException {
+ return readUnsignedByte() != 0;
+ }
+
+ /**
+ * Reads a byte from the input stream checking that the end of file (EOF)
+ * has not been encountered.
+ *
+ * @return byte read from input
+ * @throws IOException if an error is encountered while reading
+ * @throws EOFException if the end of file (EOF) is encountered.
+ */
+ private byte readAndCheckByte() throws IOException, EOFException {
+ int b1 = in.read();
+
+ if (-1 == b1) {
+ throw new EOFException();
+ }
+
+ return (byte) b1;
+ }
+
+}
diff --git a/guava/src/com/google/common/io/LittleEndianDataOutputStream.java b/guava/src/com/google/common/io/LittleEndianDataOutputStream.java
new file mode 100644
index 0000000..1725ae0
--- /dev/null
+++ b/guava/src/com/google/common/io/LittleEndianDataOutputStream.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2007 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 com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+import com.google.common.primitives.Longs;
+
+import java.io.DataOutput;
+import java.io.DataOutputStream;
+import java.io.FilterOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * An implementation of {@link DataOutput} that uses little-endian byte ordering
+ * for writing {@code char}, {@code short}, {@code int}, {@code float}, {@code
+ * double}, and {@code long} values.
+ * <p>
+ * <b>Note:</b> This class intentionally violates the specification of its
+ * supertype {@code DataOutput}, which explicitly requires big-endian byte
+ * order.
+ *
+ * @author Chris Nokleberg
+ * @author Keith Bottner
+ * @since 8.0
+ */
+@Beta
+public class LittleEndianDataOutputStream extends FilterOutputStream
+ implements DataOutput {
+
+ /**
+ * Creates a {@code LittleEndianDataOutputStream} that wraps the given stream.
+ *
+ * @param out the stream to delegate to
+ */
+ public LittleEndianDataOutputStream(OutputStream out) {
+ super(new DataOutputStream(Preconditions.checkNotNull(out)));
+ }
+
+ @Override public void write(byte[] b, int off, int len) throws IOException {
+ // Override slow FilterOutputStream impl
+ out.write(b, off, len);
+ }
+
+ @Override public void writeBoolean(boolean v) throws IOException {
+ ((DataOutputStream) out).writeBoolean(v);
+ }
+
+ @Override public void writeByte(int v) throws IOException {
+ ((DataOutputStream) out).writeByte(v);
+ }
+
+ /**
+ * @deprecated The semantics of {@code writeBytes(String s)} are considered
+ * dangerous. Please use {@link #writeUTF(String s)},
+ * {@link #writeChars(String s)} or another write method instead.
+ */
+ @Deprecated
+ @Override public void writeBytes(String s) throws IOException {
+ ((DataOutputStream) out).writeBytes(s);
+ }
+
+ /**
+ * Writes a char as specified by {@link DataOutputStream#writeChar(int)},
+ * except using little-endian byte order.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ @Override public void writeChar(int v) throws IOException {
+ writeShort(v);
+ }
+
+ /**
+ * Writes a {@code String} as specified by
+ * {@link DataOutputStream#writeChars(String)}, except each character is
+ * written using little-endian byte order.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ @Override public void writeChars(String s) throws IOException {
+ for (int i = 0; i < s.length(); i++) {
+ writeChar(s.charAt(i));
+ }
+ }
+
+ /**
+ * Writes a {@code double} as specified by
+ * {@link DataOutputStream#writeDouble(double)}, except using little-endian
+ * byte order.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ @Override public void writeDouble(double v) throws IOException {
+ writeLong(Double.doubleToLongBits(v));
+ }
+
+ /**
+ * Writes a {@code float} as specified by
+ * {@link DataOutputStream#writeFloat(float)}, except using little-endian byte
+ * order.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ @Override public void writeFloat(float v) throws IOException {
+ writeInt(Float.floatToIntBits(v));
+ }
+
+ /**
+ * Writes an {@code int} as specified by
+ * {@link DataOutputStream#writeInt(int)}, except using little-endian byte
+ * order.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ @Override public void writeInt(int v) throws IOException {
+ out.write(0xFF & v);
+ out.write(0xFF & (v >> 8));
+ out.write(0xFF & (v >> 16));
+ out.write(0xFF & (v >> 24));
+ }
+
+ /**
+ * Writes a {@code long} as specified by
+ * {@link DataOutputStream#writeLong(long)}, except using little-endian byte
+ * order.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ @Override public void writeLong(long v) throws IOException {
+ byte[] bytes = Longs.toByteArray(Long.reverseBytes(v));
+ write(bytes, 0, bytes.length);
+ }
+
+ /**
+ * Writes a {@code short} as specified by
+ * {@link DataOutputStream#writeShort(int)}, except using little-endian byte
+ * order.
+ *
+ * @throws IOException if an I/O error occurs
+ */
+ @Override public void writeShort(int v) throws IOException {
+ out.write(0xFF & v);
+ out.write(0xFF & (v >> 8));
+ }
+
+ @Override public void writeUTF(String str) throws IOException {
+ ((DataOutputStream) out).writeUTF(str);
+ }
+}
diff --git a/guava/src/com/google/common/io/MultiInputStream.java b/guava/src/com/google/common/io/MultiInputStream.java
new file mode 100644
index 0000000..f8f1a0b
--- /dev/null
+++ b/guava/src/com/google/common/io/MultiInputStream.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2007 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 java.io.IOException;
+import java.io.InputStream;
+import java.util.Iterator;
+
+/**
+ * An {@link InputStream} that concatenates multiple substreams. At most
+ * one stream will be open at a time.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+final class MultiInputStream extends InputStream {
+
+ private Iterator<? extends InputSupplier<? extends InputStream>> it;
+ private InputStream in;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param it an iterator of I/O suppliers that will provide each substream
+ */
+ public MultiInputStream(
+ Iterator<? extends InputSupplier<? extends InputStream>> it)
+ throws IOException {
+ this.it = it;
+ advance();
+ }
+
+ @Override public void close() throws IOException {
+ if (in != null) {
+ try {
+ in.close();
+ } finally {
+ in = null;
+ }
+ }
+ }
+
+ /**
+ * Closes the current input stream and opens the next one, if any.
+ */
+ private void advance() throws IOException {
+ close();
+ if (it.hasNext()) {
+ in = it.next().getInput();
+ }
+ }
+
+ @Override public int available() throws IOException {
+ if (in == null) {
+ return 0;
+ }
+ return in.available();
+ }
+
+ @Override public boolean markSupported() {
+ return false;
+ }
+
+ @Override public int read() throws IOException {
+ if (in == null) {
+ return -1;
+ }
+ int result = in.read();
+ if (result == -1) {
+ advance();
+ return read();
+ }
+ return result;
+ }
+
+ @Override public int read(byte[] b, int off, int len) throws IOException {
+ if (in == null) {
+ return -1;
+ }
+ int result = in.read(b, off, len);
+ if (result == -1) {
+ advance();
+ return read(b, off, len);
+ }
+ return result;
+ }
+
+ @Override public long skip(long n) throws IOException {
+ if (in == null || n <= 0) {
+ return 0;
+ }
+ long result = in.skip(n);
+ if (result != 0) {
+ return result;
+ }
+ if (read() == -1) {
+ return 0;
+ }
+ return 1 + in.skip(n - 1);
+ }
+}
diff --git a/guava/src/com/google/common/io/MultiReader.java b/guava/src/com/google/common/io/MultiReader.java
new file mode 100644
index 0000000..6757a26
--- /dev/null
+++ b/guava/src/com/google/common/io/MultiReader.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008 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 com.google.common.base.Preconditions;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Iterator;
+
+/**
+ * A {@link Reader} that concatenates multiple readers.
+ *
+ * @author Bin Zhu
+ * @since 1.0
+ */
+class MultiReader extends Reader {
+ private final Iterator<? extends InputSupplier<? extends Reader>> it;
+ private Reader current;
+
+ MultiReader(Iterator<? extends InputSupplier<? extends Reader>> readers)
+ throws IOException {
+ this.it = readers;
+ advance();
+ }
+
+ /**
+ * Closes the current reader and opens the next one, if any.
+ */
+ private void advance() throws IOException {
+ close();
+ if (it.hasNext()) {
+ current = it.next().getInput();
+ }
+ }
+
+ @Override public int read(char cbuf[], int off, int len) throws IOException {
+ if (current == null) {
+ return -1;
+ }
+ int result = current.read(cbuf, off, len);
+ if (result == -1) {
+ advance();
+ return read(cbuf, off, len);
+ }
+ return result;
+ }
+
+ @Override public long skip(long n) throws IOException {
+ Preconditions.checkArgument(n >= 0, "n is negative");
+ if (n > 0) {
+ while (current != null) {
+ long result = current.skip(n);
+ if (result > 0) {
+ return result;
+ }
+ advance();
+ }
+ }
+ return 0;
+ }
+
+ @Override public boolean ready() throws IOException {
+ return (current != null) && current.ready();
+ }
+
+ @Override public void close() throws IOException {
+ if (current != null) {
+ try {
+ current.close();
+ } finally {
+ current = null;
+ }
+ }
+ }
+}
diff --git a/guava/src/com/google/common/io/NullOutputStream.java b/guava/src/com/google/common/io/NullOutputStream.java
new file mode 100644
index 0000000..1c1e98e
--- /dev/null
+++ b/guava/src/com/google/common/io/NullOutputStream.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2004 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 com.google.common.annotations.Beta;
+
+import java.io.OutputStream;
+
+/**
+ * Implementation of {@link OutputStream} that simply discards written bytes.
+ *
+ * @author Spencer Kimball
+ * @since 1.0
+ */
+@Beta
+public final class NullOutputStream extends OutputStream {
+ /** Discards the specified byte. */
+ @Override public void write(int b) {
+ }
+
+ /** Discards the specified byte array. */
+ @Override public void write(byte[] b, int off, int len) {
+ }
+}
diff --git a/guava/src/com/google/common/io/OutputSupplier.java b/guava/src/com/google/common/io/OutputSupplier.java
new file mode 100644
index 0000000..185082c
--- /dev/null
+++ b/guava/src/com/google/common/io/OutputSupplier.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2007 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 java.io.IOException;
+
+/**
+ * A factory for writable streams of bytes or characters.
+ *
+ * @author Chris Nokleberg
+ * @since 1.0
+ */
+public interface OutputSupplier<T> {
+
+ /**
+ * Returns an object that encapsulates a writable resource.
+ * <p>
+ * Like {@link Iterable#iterator}, this method may be called repeatedly to
+ * get independent channels to the same underlying resource.
+ * <p>
+ * Where the channel maintains a position within the resource, moving that
+ * cursor within one channel should not affect the starting position of
+ * channels returned by other calls.
+ */
+ T getOutput() throws IOException;
+}
diff --git a/guava/src/com/google/common/io/PatternFilenameFilter.java b/guava/src/com/google/common/io/PatternFilenameFilter.java
new file mode 100644
index 0000000..2859277
--- /dev/null
+++ b/guava/src/com/google/common/io/PatternFilenameFilter.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2006 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 com.google.common.annotations.Beta;
+import com.google.common.base.Preconditions;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+import javax.annotation.Nullable;
+
+/**
+ * File name filter that only accepts files matching a regular expression. This
+ * class is thread-safe and immutable.
+ *
+ * @author Apple Chow
+ * @since 1.0
+ */
+@Beta
+public final class PatternFilenameFilter implements FilenameFilter {
+
+ private final Pattern pattern;
+
+ /**
+ * Constructs a pattern file name filter object.
+ * @param patternStr the pattern string on which to filter file names
+ *
+ * @throws PatternSyntaxException if pattern compilation fails (runtime)
+ */
+ public PatternFilenameFilter(String patternStr) {
+ this(Pattern.compile(patternStr));
+ }
+
+ /**
+ * Constructs a pattern file name filter object.
+ * @param pattern the pattern on which to filter file names
+ */
+ public PatternFilenameFilter(Pattern pattern) {
+ this.pattern = Preconditions.checkNotNull(pattern);
+ }
+
+ @Override public boolean accept(@Nullable File dir, String fileName) {
+ return pattern.matcher(fileName).matches();
+ }
+}
diff --git a/guava/src/com/google/common/io/Resources.java b/guava/src/com/google/common/io/Resources.java
new file mode 100644
index 0000000..1bb8067
--- /dev/null
+++ b/guava/src/com/google/common/io/Resources.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2007 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 com.google.common.annotations.Beta;
+import com.google.common.base.Charsets;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.List;
+
+/**
+ * Provides utility methods for working with resources in the classpath.
+ * Note that even though these methods use {@link URL} parameters, they
+ * are usually not appropriate for HTTP or other non-classpath resources.
+ *
+ * <p>All method parameters must be non-null unless documented otherwise.
+ *
+ * @author Chris Nokleberg
+ * @author Ben Yu
+ * @since 1.0
+ */
+@Beta
+public final class Resources {
+ private Resources() {}
+
+ /**
+ * Returns a factory that will supply instances of {@link InputStream} that
+ * read from the given URL.
+ *
+ * @param url the URL to read from
+ * @return the factory
+ */
+ public static InputSupplier<InputStream> newInputStreamSupplier(
+ final URL url) {
+ checkNotNull(url);
+ return new InputSupplier<InputStream>() {
+ @Override
+ public InputStream getInput() throws IOException {
+ return url.openStream();
+ }
+ };
+ }
+
+ /**
+ * Returns a factory that will supply instances of
+ * {@link InputStreamReader} that read a URL using the given character set.
+ *
+ * @param url the URL to read from
+ * @param charset the charset used to decode the input stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @return the factory
+ */
+ public static InputSupplier<InputStreamReader> newReaderSupplier(
+ URL url, Charset charset) {
+ return CharStreams.newReaderSupplier(newInputStreamSupplier(url), charset);
+ }
+
+ /**
+ * Reads all bytes from a URL into a byte array.
+ *
+ * @param url the URL to read from
+ * @return a byte array containing all the bytes from the URL
+ * @throws IOException if an I/O error occurs
+ */
+ public static byte[] toByteArray(URL url) throws IOException {
+ return ByteStreams.toByteArray(newInputStreamSupplier(url));
+ }
+
+ /**
+ * Reads all characters from a URL into a {@link String}, using the given
+ * character set.
+ *
+ * @param url the URL to read from
+ * @param charset the charset used to decode the input stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @return a string containing all the characters from the URL
+ * @throws IOException if an I/O error occurs.
+ */
+ public static String toString(URL url, Charset charset) throws IOException {
+ return CharStreams.toString(newReaderSupplier(url, charset));
+ }
+
+ /**
+ * Streams lines from a URL, stopping when our callback returns false, or we
+ * have read all of the lines.
+ *
+ * @param url the URL to read from
+ * @param charset the charset used to decode the input stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @param callback the LineProcessor to use to handle the lines
+ * @return the output of processing the lines
+ * @throws IOException if an I/O error occurs
+ */
+ public static <T> T readLines(URL url, Charset charset,
+ LineProcessor<T> callback) throws IOException {
+ return CharStreams.readLines(newReaderSupplier(url, charset), callback);
+ }
+
+ /**
+ * Reads all of the lines from a URL. The lines do not include
+ * line-termination characters, but do include other leading and trailing
+ * whitespace.
+ *
+ * @param url the URL to read from
+ * @param charset the charset used to decode the input stream; see {@link
+ * Charsets} for helpful predefined constants
+ * @return a mutable {@link List} containing all the lines
+ * @throws IOException if an I/O error occurs
+ */
+ public static List<String> readLines(URL url, Charset charset)
+ throws IOException {
+ return CharStreams.readLines(newReaderSupplier(url, charset));
+ }
+
+ /**
+ * Copies all bytes from a URL to an output stream.
+ *
+ * @param from the URL to read from
+ * @param to the output stream
+ * @throws IOException if an I/O error occurs
+ */
+ public static void copy(URL from, OutputStream to) throws IOException {
+ ByteStreams.copy(newInputStreamSupplier(from), to);
+ }
+
+ /**
+ * Returns a {@code URL} pointing to {@code resourceName} if the resource is
+ * found in the class path. {@code Resources.class.getClassLoader()} is used
+ * to locate the resource.
+ *
+ * @throws IllegalArgumentException if resource is not found
+ */
+ public static URL getResource(String resourceName) {
+ URL url = Resources.class.getClassLoader().getResource(resourceName);
+ checkArgument(url != null, "resource %s not found.", resourceName);
+ return url;
+ }
+
+ /**
+ * Returns a {@code URL} pointing to {@code resourceName} that is relative to
+ * {@code contextClass}, if the resource is found in the class path.
+ *
+ * @throws IllegalArgumentException if resource is not found
+ */
+ public static URL getResource(Class<?> contextClass, String resourceName) {
+ URL url = contextClass.getResource(resourceName);
+ checkArgument(url != null, "resource %s relative to %s not found.",
+ resourceName, contextClass.getName());
+ return url;
+ }
+}
diff --git a/guava/src/com/google/common/io/package-info.java b/guava/src/com/google/common/io/package-info.java
new file mode 100644
index 0000000..f5f83ad
--- /dev/null
+++ b/guava/src/com/google/common/io/package-info.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+/**
+ * This package contains utility methods and classes for working with Java I/O,
+ * for example input streams, output streams, readers, writers, and files.
+ *
+ * <p>Many of the methods are based on the
+ * {@link com.google.common.io.InputSupplier} and
+ * {@link com.google.common.io.OutputSupplier} interfaces. They are used as
+ * factories for I/O objects that might throw {@link java.io.IOException} when
+ * being created. The advantage of using a factory is that the helper methods in
+ * this package can take care of closing the resource properly, even if an
+ * exception is thrown. The {@link com.google.common.io.ByteStreams},
+ * {@link com.google.common.io.CharStreams}, and
+ * {@link com.google.common.io.Files} classes all have static helper methods to
+ * create new factories and to work with them.
+ *
+ * <p>This package is a part of the open-source
+ * <a href="http://guava-libraries.googlecode.com">Guava libraries</a>.
+ *
+ * @author Chris Nokleberg
+ */
+@ParametersAreNonnullByDefault
+package com.google.common.io;
+
+import javax.annotation.ParametersAreNonnullByDefault;
+