diff options
Diffstat (limited to 'org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java')
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java | 280 |
1 files changed, 127 insertions, 153 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java index c817c475aa..8cc5316271 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/IO.java @@ -1,56 +1,23 @@ /* * Copyright (C) 2008-2009, Google Inc. * Copyright (C) 2009, Robin Rosenberg <robin.rosenberg@dewire.com> - * Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org> - * and other copyright owners as documented in the project's IP log. + * Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org> and others * - * This program and the accompanying materials are made available - * under the terms of the Eclipse Distribution License v1.0 which - * accompanies this distribution, is reproduced below, and is - * available at http://www.eclipse.org/org/documents/edl-v10.php + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following - * conditions are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * - * - Neither the name of the Eclipse Foundation, Inc. nor the - * names of its contributors may be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, - * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * SPDX-License-Identifier: BSD-3-Clause */ package org.eclipse.jgit.util; import java.io.EOFException; import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.io.Reader; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; import java.text.MessageFormat; @@ -58,6 +25,7 @@ import java.util.ArrayList; import java.util.List; import org.eclipse.jgit.internal.JGitText; +import org.eclipse.jgit.util.io.SilentFileInputStream; /** * Input/Output utilities @@ -70,12 +38,12 @@ public class IO { * @param path * location of the file to read. * @return complete contents of the requested local file. - * @throws FileNotFoundException + * @throws java.io.FileNotFoundException * the file does not exist. - * @throws IOException + * @throws java.io.IOException * the file exists, but its contents cannot be read. */ - public static final byte[] readFully(final File path) + public static final byte[] readFully(File path) throws FileNotFoundException, IOException { return IO.readFully(path, Integer.MAX_VALUE); } @@ -90,34 +58,15 @@ public class IO { * only the first limit number of bytes are returned * @return complete contents of the requested local file. If the contents * exceeds the limit, then only the limit is returned. - * @throws FileNotFoundException + * @throws java.io.FileNotFoundException * the file does not exist. - * @throws IOException + * @throws java.io.IOException * the file exists, but its contents cannot be read. */ - public static final byte[] readSome(final File path, final int limit) + public static final byte[] readSome(File path, int limit) throws FileNotFoundException, IOException { - FileInputStream in = new FileInputStream(path); - try { - byte[] buf = new byte[limit]; - int cnt = 0; - for (;;) { - int n = in.read(buf, cnt, buf.length - cnt); - if (n <= 0) - break; - cnt += n; - } - if (cnt == buf.length) - return buf; - byte[] res = new byte[cnt]; - System.arraycopy(buf, 0, res, 0, cnt); - return res; - } finally { - try { - in.close(); - } catch (IOException ignored) { - // do nothing - } + try (SilentFileInputStream in = new SilentFileInputStream(path)) { + return in.readNBytes(limit); } } @@ -130,54 +79,20 @@ public class IO { * maximum number of bytes to read, if the file is larger than * this limit an IOException is thrown. * @return complete contents of the requested local file. - * @throws FileNotFoundException + * @throws java.io.FileNotFoundException * the file does not exist. - * @throws IOException + * @throws java.io.IOException * the file exists, but its contents cannot be read. */ - public static final byte[] readFully(final File path, final int max) + public static final byte[] readFully(File path, int max) throws FileNotFoundException, IOException { - final FileInputStream in = new FileInputStream(path); - try { - long sz = Math.max(path.length(), 1); - if (sz > max) + try (SilentFileInputStream in = new SilentFileInputStream(path)) { + byte[] buf = in.readNBytes(max); + if (in.read() != -1) { throw new IOException(MessageFormat.format( JGitText.get().fileIsTooLarge, path)); - - byte[] buf = new byte[(int) sz]; - int valid = 0; - for (;;) { - if (buf.length == valid) { - if (buf.length == max) { - int next = in.read(); - if (next < 0) - break; - - throw new IOException(MessageFormat.format( - JGitText.get().fileIsTooLarge, path)); - } - - byte[] nb = new byte[Math.min(buf.length * 2, max)]; - System.arraycopy(buf, 0, nb, 0, valid); - buf = nb; - } - int n = in.read(buf, valid, buf.length - valid); - if (n < 0) - break; - valid += n; - } - if (valid < buf.length) { - byte[] nb = new byte[valid]; - System.arraycopy(buf, 0, nb, 0, valid); - buf = nb; } return buf; - } finally { - try { - in.close(); - } catch (IOException ignored) { - // ignore any close errors, this was a read only stream - } } } @@ -198,30 +113,12 @@ public class IO { * on obtaining the underlying array for efficient data access. If * {@code sizeHint} was too large, the array may be over-allocated, * resulting in {@code limit() < array().length}. - * @throws IOException + * @throws java.io.IOException * there was an error reading from the stream. */ public static ByteBuffer readWholeStream(InputStream in, int sizeHint) throws IOException { - byte[] out = new byte[sizeHint]; - int pos = 0; - while (pos < out.length) { - int read = in.read(out, pos, out.length - pos); - if (read < 0) - return ByteBuffer.wrap(out, 0, pos); - pos += read; - } - - int last = in.read(); - if (last < 0) - return ByteBuffer.wrap(out, 0, pos); - - @SuppressWarnings("resource" /* java 7 */) - TemporaryBuffer.Heap tmp = new TemporaryBuffer.Heap(Integer.MAX_VALUE); - tmp.write(out); - tmp.write(last); - tmp.copy(in); - return ByteBuffer.wrap(tmp.toByteArray()); + return ByteBuffer.wrap(in.readAllBytes()); } /** @@ -237,18 +134,33 @@ public class IO { * number of bytes that must be read. * @throws EOFException * the stream ended before dst was fully populated. - * @throws IOException + * @throws java.io.IOException * there was an error reading from the stream. */ public static void readFully(final InputStream fd, final byte[] dst, int off, int len) throws IOException { - while (len > 0) { - final int r = fd.read(dst, off, len); - if (r <= 0) - throw new EOFException(JGitText.get().shortReadOfBlock); - off += r; - len -= r; - } + int read = fd.readNBytes(dst, off, len); + if (read != len) + throw new EOFException(JGitText.get().shortReadOfBlock); + } + + /** + * Read from input until the entire byte array filled, or throw an exception + * if stream ends first. + * + * @param fd + * input stream to read the data from. + * @param dst + * buffer that must be fully populated + * @throws EOFException + * the stream ended before dst was fully populated. + * @throws java.io.IOException + * there was an error reading from the stream. + * @since 6.5 + */ + public static void readFully(InputStream fd, byte[] dst) + throws IOException { + readFully(fd, dst, 0, dst.length); } /** @@ -263,7 +175,7 @@ public class IO { * @param len * number of bytes that should be read. * @return number of bytes actually read. - * @throws IOException + * @throws java.io.IOException * there was an error reading from the channel. */ public static int read(ReadableByteChannel channel, byte[] dst, int off, @@ -291,20 +203,13 @@ public class IO { * buffer that must be fully populated, [off, off+len). * @param off * position within the buffer to start writing to. - * @return number of bytes in buffer or stream, whichever is shortest - * @throws IOException + * @return number of bytes read + * @throws java.io.IOException * there was an error reading from the stream. */ public static int readFully(InputStream fd, byte[] dst, int off) throws IOException { - int r; - int len = 0; - while ((r = fd.read(dst, off, dst.length - off)) >= 0 - && len < dst.length) { - off += r; - len += r; - } - return len; + return fd.readNBytes(dst, off, dst.length - off); } /** @@ -321,11 +226,12 @@ public class IO { * @throws EOFException * the stream ended before the requested number of bytes were * skipped. - * @throws IOException + * @throws java.io.IOException * there was an error reading from the stream. */ - public static void skipFully(final InputStream fd, long toSkip) + public static void skipFully(InputStream fd, long toSkip) throws IOException { + // same as fd.skipNBytes(toSkip) of JDK 12; while (toSkip > 0) { final long r = fd.skip(toSkip); if (r <= 0) @@ -342,8 +248,8 @@ public class IO { * @return the string divided into lines * @since 2.0 */ - public static List<String> readLines(final String s) { - List<String> l = new ArrayList<String>(); + public static List<String> readLines(String s) { + List<String> l = new ArrayList<>(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); @@ -357,13 +263,14 @@ public class IO { c = s.charAt(++i); l.add(sb.toString()); sb.setLength(0); - if (c != '\n') + if (c != '\n') { sb.append(c); + } continue; - } else { // EOF - l.add(sb.toString()); - break; } + // EOF + l.add(sb.toString()); + break; } sb.append(c); } @@ -371,6 +278,73 @@ public class IO { return l; } + /** + * Read the next line from a reader. + * <p> + * Like {@link java.io.BufferedReader#readLine()}, but only treats + * {@code \n} as end-of-line, and includes the trailing newline. + * + * @param in + * the reader to read from. + * @param sizeHint + * hint for buffer sizing; 0 or negative for default. + * @return the next line from the input, always ending in {@code \n} unless + * EOF was reached. + * @throws java.io.IOException + * there was an error reading from the stream. + * @since 4.1 + */ + public static String readLine(Reader in, int sizeHint) throws IOException { + if (in.markSupported()) { + if (sizeHint <= 0) { + sizeHint = 1024; + } + StringBuilder sb = new StringBuilder(sizeHint); + char[] buf = new char[sizeHint]; + while (true) { + in.mark(sizeHint); + int n = in.read(buf); + if (n < 0) { + in.reset(); + return sb.toString(); + } + for (int i = 0; i < n; i++) { + if (buf[i] == '\n') { + resetAndSkipFully(in, ++i); + sb.append(buf, 0, i); + return sb.toString(); + } + } + if (n > 0) { + sb.append(buf, 0, n); + } + resetAndSkipFully(in, n); + } + } + StringBuilder buf = sizeHint > 0 ? new StringBuilder(sizeHint) + : new StringBuilder(); + int i; + while ((i = in.read()) != -1) { + char c = (char) i; + buf.append(c); + if (c == '\n') { + break; + } + } + return buf.toString(); + } + + private static void resetAndSkipFully(Reader fd, long toSkip) throws IOException { + fd.reset(); + while (toSkip > 0) { + long r = fd.skip(toSkip); + if (r <= 0) { + throw new EOFException(JGitText.get().shortSkipOfBlock); + } + toSkip -= r; + } + } + private IO() { // Don't create instances of a static only utility. } |