content: /*
   * Licensed to the Apache Software Foundation (ASF) under one or more
   * contributor license agreements.  See the NOTICE file distributed with
   * this work for additional information regarding copyright ownership.
   * The ASF licenses this file to You 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 org.libtorrent4j;
  
  import java.io.Closeable;
  import java.io.File;
  import java.io.FileInputStream;
  import java.io.FileNotFoundException;
  import java.io.IOException;
  import java.io.InputStream;
  
  final class Files {
  
      private Files() {
      }
  
      private static final int EOF = -1;
  
      /**
       * Reads the contents of a file into a byte array.
       * The file is always closed.
       *
       * @param file the file to read, must not be {@code null}
       * @return the file contents, never {@code null}
       * @throws IOException in case of an I/O error
       * @since 1.1
       */
      public static byte[] bytes(File file) throws IOException {
          InputStream in = null;
          try {
              in = openInputStream(file);
              return toByteArray(in, file.length());
          } finally {
              closeQuietly(in);
          }
      }
  
      /**
       * Opens a {@link java.io.FileInputStream} for the specified file, providing better
       * error messages than simply calling <code>new FileInputStream(file)</code>.
       * <p>
       * At the end of the method either the stream will be successfully opened,
       * or an exception will have been thrown.
       * <p>
       * An exception is thrown if the file does not exist.
       * An exception is thrown if the file object exists but is a directory.
       * An exception is thrown if the file exists but cannot be read.
       *
       * @param file the file to open for input, must not be {@code null}
       * @return a new {@link java.io.FileInputStream} for the specified file
       * @throws java.io.FileNotFoundException if the file does not exist
       * @throws IOException                   if the file object is a directory
       * @throws IOException                   if the file cannot be read
       * @since 1.3
       */
      private static FileInputStream openInputStream(File file) throws IOException {
          if (file.exists()) {
              if (file.isDirectory()) {
                  throw new IOException("File '" + file + "' exists but is a directory");
              }
              if (file.canRead() == false) {
                  throw new IOException("File '" + file + "' cannot be read");
              }
          } else {
              throw new FileNotFoundException("File '" + file + "' does not exist");
          }
          return new FileInputStream(file);
      }
  
      /**
       * Get contents of an <code>InputStream</code> as a <code>byte[]</code>.
       * Use this method instead of <code>toByteArray(InputStream)</code>
       * when <code>InputStream</code> size is known.
       * <b>NOTE:</b> the method checks that the length can safely be cast to an int without truncation
       * before using {@link #toByteArray(java.io.InputStream, int)} to read into the byte array.
       * (Arrays can have no more than Integer.MAX_VALUE entries anyway)
       *
       * @param input the <code>InputStream</code> to read from
       * @param size  the size of <code>InputStream</code>
       * @return the requested byte array
       * @throws IOException              if an I/O error occurs or <code>InputStream</code> size differ from parameter size
       * @throws IllegalArgumentException if size is less than zero or size is greater than Integer.MAX_VALUE
       * @see #toByteArray(java.io.InputStream, int)
       * @since 2.1
       */
      private static byte[] toByteArray(InputStream input, long size) throws IOException {
  
          if (size > Integer.MAX_VALUE) {
              throw new IllegalArgumentException("Size cannot be greater than Integer max value: " + size);
          }
  
          return toByteArray(input, (int) size);
      }
  
      /**
       * Get the contents of an <code>InputStream</code> as a <code>byte[]</code>.
       * Use this method instead of <code>toByteArray(InputStream)</code>
       * when <code>InputStream</code> size is known
       *
       * @param input the <code>InputStream</code> to read from
       * @param size  the size of <code>InputStream</code>
       * @return the requested byte array
       * @throws java.io.IOException      if an I/O error occurs or <code>InputStream</code> size differ from parameter size
       * @throws IllegalArgumentException if size is less than zero
       * @since 2.1
       */
      private static byte[] toByteArray(InputStream input, int size) throws IOException {
  
          if (size < 0) {
              throw new IllegalArgumentException("Size must be equal or greater than zero: " + size);
          }
  
          if (size == 0) {
              return new byte[0];
          }
  
          byte[] data = new byte[size];
          int offset = 0;
          int readed;
  
          while (offset < size && (readed = input.read(data, offset, size - offset)) != EOF) {
              offset += readed;
          }
  
          if (offset != size) {
              throw new IOException("Unexpected readed size. current: " + offset + ", excepted: " + size);
          }
  
          return data;
      }
  
      /**
       * Unconditionally close an <code>InputStream</code>.
       * <p>
       * Equivalent to {@link InputStream#close()}, except any exceptions will be ignored.
       * This is typically used in finally blocks.
       * <p>
       * Example code:
       * <pre>
       *   byte[] data = new byte[1024];
       *   InputStream in = null;
       *   try {
       *       in = new FileInputStream("foo.txt");
       *       in.read(data);
       *       in.close(); //close errors are handled
       *   } catch (Exception e) {
       *       // error handling
       *   } finally {
       *       IOUtils.closeQuietly(in);
       *   }
       * </pre>
       *
       * @param input the InputStream to close, may be null or already closed
       */
      static void closeQuietly(InputStream input) {
          closeQuietly((Closeable) input);
      }
  
      /**
       * Unconditionally close a <code>Closeable</code>.
       * <p>
       * Equivalent to {@link java.io.Closeable#close()}, except any exceptions will be ignored.
       * This is typically used in finally blocks.
       * <p>
       * Example code:
       * <pre>
       *   Closeable closeable = null;
       *   try {
       *       closeable = new FileReader("foo.txt");
       *       // process closeable
       *       closeable.close();
       *   } catch (Exception e) {
       *       // error handling
       *   } finally {
       *       IOUtils.closeQuietly(closeable);
       *   }
       * </pre>
       *
       * @param closeable the object to close, may be null or already closed
       * @since 2.0
       */
      static void closeQuietly(Closeable closeable) {
          try {
              if (closeable != null) {
                  closeable.close();
              }
          } catch (IOException ioe) {
              // ignore
          }
      }
  }
  