/*
 * This file is part of dependency-check-utils.
 *
 * 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.
 *
 * Copyright (c) 2012 Jeremy Long. All Rights Reserved.
 */
package org.owasp.dependencycheck.utils;

import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.SystemUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * A collection of utilities for processing information about files.
 *
 * @author Jeremy Long
 */
public final class FileUtils {

    /**
     * The logger.
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(FileUtils.class);
    /**
     * Bit bucket for non-Windows systems
     */
    private static final String BIT_BUCKET_UNIX = "/dev/null";

    /**
     * Bit bucket for Windows systems (yes, only one 'L')
     */
    private static final String BIT_BUCKET_WIN = "NUL";

    /**
     * Private constructor for a utility class.
     */
    private FileUtils() {
    }

    /**
     * Returns the (lowercase) file extension for a specified file.
     *
     * @param fileName the file name to retrieve the file extension from.
     * @return the file extension.
     */
    @Nullable
    public static String getFileExtension(@NotNull String fileName) {
        @Nullable
        final String fileExt = FilenameUtils.getExtension(fileName);
        return StringUtils.isNoneEmpty(fileExt) ? StringUtils.lowerCase(fileExt) : null;
    }

    /**
     * Deletes a file. If the File is a directory it will recursively delete the
     * contents.
     *
     * @param file the File to delete
     * @return true if the file was deleted successfully, otherwise false
     */
    public static boolean delete(@Nullable File file) {
        if (file == null) {
            LOGGER.warn("cannot delete null File");
            return false;
        }

        try {
            org.apache.commons.io.FileUtils.forceDelete(file);
        } catch (IOException ex) {
            LOGGER.trace(ex.getMessage(), ex);
            LOGGER.debug("Failed to delete file: {} (error message: {}); attempting to delete on exit.", file.getPath(), ex.getMessage());
            file.deleteOnExit();
            return false;
        }

        return true;
    }

    /**
     * Creates a unique temporary directory in the given directory.
     *
     * @param base the base directory to create a temporary directory within
     * @return the temporary directory
     * @throws java.io.IOException thrown when a directory cannot be created
     * within the base directory
     */
    @NotNull
    public static File createTempDirectory(@Nullable final File base) throws IOException {
        final File tempDir = new File(base, "dctemp" + UUID.randomUUID().toString());
        if (tempDir.exists()) {
            return createTempDirectory(base);
        }
        if (!tempDir.mkdirs()) {
            throw new IOException("Could not create temp directory `" + tempDir.getAbsolutePath() + "`");
        }
        LOGGER.debug("Temporary directory is `{}`", tempDir.getAbsolutePath());
        return tempDir;
    }

    /**
     * Return the bit bucket for the OS. '/dev/null' for Unix and 'NUL' for
     * Windows
     *
     * @return a String containing the bit bucket
     */
    @NotNull
    public static String getBitBucket() {
        return SystemUtils.IS_OS_WINDOWS ? BIT_BUCKET_WIN : BIT_BUCKET_UNIX;
    }

    /**
     * Close the given {@link java.io.Closeable} instance, ignoring nulls, and
     * logging any thrown {@link java.io.IOException}.
     *
     * @param closeable to be closed
     */
    public static void close(@Nullable final Closeable closeable) {
        if (null != closeable) {
            try {
                closeable.close();
            } catch (IOException ex) {
                LOGGER.trace("", ex);
            }
        }
    }

    /**
     * Gets the {@link java.io.InputStream} for this resource.
     *
     * @param resource path
     * @return the input stream for the given resource
     */
    @Nullable
    public static InputStream getResourceAsStream(@NotNull String resource) {
        final ClassLoader classLoader = FileUtils.class.getClassLoader();
        final InputStream inputStream = classLoader != null
                ? classLoader.getResourceAsStream(resource)
                : ClassLoader.getSystemResourceAsStream(resource);

        if (inputStream == null) {
            try {
                return new FileInputStream(resource);
            } catch (final FileNotFoundException e) {
                LOGGER.error("Unable to create an Input Stream for " + resource, e);
            }
        }
        return inputStream;
    }

    /**
     * Returns a File object for the given resource. The resource is attempted
     * to be loaded from the class loader.
     *
     * @param resource path
     * @return the file reference for the resource
     */
    public static File getResourceAsFile(final String resource) {
        final ClassLoader classLoader = FileUtils.class.getClassLoader();
        final String path = classLoader != null
                ? classLoader.getResource(resource).getFile()
                : ClassLoader.getSystemResource(resource).getFile();

        if (path == null) {
            return new File(resource);
        }
        return new File(path);
    }
}

@@ -872,32 +872,53 @@
 io.InputStream;%0A
+import java.net.URL;%0A
 import java.util
@@ -5886,30 +5886,24 @@
 ();%0A        
-final 
 String path 
@@ -5904,16 +5904,34 @@
  path = 
+null;%0A        if (
 classLoa
@@ -5933,34 +5933,36 @@
 ssLoader != null
+) %7B
 %0A
- 
                ?
@@ -5949,36 +5949,41 @@
 ) %7B%0A            
-   ?
+URL url =
  classLoader.get
@@ -5992,32 +5992,91 @@
 source(resource)
+;%0A            if (url != null) %7B%0A                path = url
 .getFile()%0A     
@@ -6069,16 +6069,17 @@
 etFile()
+;
 %0A       
@@ -6075,37 +6075,69 @@
 ();%0A            
-    :
+%7D%0A        %7D else %7B%0A            path =
  ClassLoader.get
@@ -6171,16 +6171,26 @@
 tFile();
+%0A        %7D
 %0A%0A      

Fix NullPointerException in case classLoader.getResource() returns null (#2971)