/*
 * Autopsy Forensic Browser
 *
 * Copyright 2013 Basis Technology Corp.
 * Contact: carrier <at> sleuthkit <dot> org
 *
 * 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 org.sleuthkit.autopsy.scalpel.jni;

import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.ReadContentInputStream;

/**
 * JNI wrapper over libscalpel and library loader
 */
public class ScalpelCarver {

    private static final String SCALPEL_JNI_LIB = "libscalpel_jni";
    private static volatile ScalpelCarver instance;
    private boolean initialized = false;
    private static final Logger logger = Logger.getLogger(ScalpelCarver.class.getName());

    private static native void carveNat(ReadContentInputStream input, String configFilePath, String outputFolderPath) throws ScalpelException;

    private ScalpelCarver() {
        init();
    }

    /**
     * initialize, load dynamic libraries
     */
    private void init() {
        try {
            //rely on netbeans / jna to locate the lib variation for architecture/OS
            System.loadLibrary(SCALPEL_JNI_LIB);
            initialized = true;
        } catch (UnsatisfiedLinkError ex) {
            initialized = false;
            String msg = "Could not load " + SCALPEL_JNI_LIB + " for your environment ";
            System.out.println(msg + ex.toString());
            logger.log(Level.SEVERE, msg, ex);
        } catch (Exception ex) {
            initialized = false;
            String msg = "Could not load " + SCALPEL_JNI_LIB + " for your environment ";
            System.out.println(msg + ex.toString());
            logger.log(Level.SEVERE, msg, ex);
        }
    }

    /**
     * Singleton getter for ScalpelCarver. Initializes and returns a
     * ready-instance of scalpel wrapper.
     *
     * @return ScalpelCarver instance
     */
    public static ScalpelCarver getInstance() {
        if (instance == null) {
            synchronized (ScalpelCarver.class) {
                if (instance == null) {
                    instance = new ScalpelCarver();
                }
            }
        }

        return instance;
    }

    /**
     * Check if initialized
     *
     * @return true if library has been initialized properly, false otherwise
     */
    public boolean isInitialized() {
        return initialized;
    }

    /**
     * Carve the file passed in as an argument and save the results.
     *
     * TODO consider returning a data structure representing carved files.
     *
     * @param file File to carve #param configFilePath file path to scalpel
     * configuration file with signatures, such as scalpel.conf
     * @param outputFolder Location to save the reults to (should be in the case
     * folder)
     * @throws ScalpelException on errors
     */
    public void carve(AbstractFile file, String configFilePath, String outputFolderPath) throws ScalpelException {
        if (!initialized) {
            throw new ScalpelException("Scalpel library is not fully initialized. ");
        }
        
        //basic check of arguments before going to jni land
        if (file == null || configFilePath == null || configFilePath.isEmpty()
                || outputFolderPath == null || outputFolderPath.isEmpty() ) {
            throw new ScalpelException("Invalid arguments for scalpel carving. ");
        }

        final ReadContentInputStream carverInput = new ReadContentInputStream(file);
        
        carveNat(carverInput, configFilePath, outputFolderPath);
    }
}

@@ -719,16 +719,41 @@
 l.jni;%0A%0A
+import java.util.Arrays;%0A
 import j
@@ -1453,32 +1453,599 @@
  init();%0A    %7D%0A%0A
+    private void init() %7B%0A        initialized = true;%0A        for (String library : Arrays.asList(%22libtre-4%22, %22pthreadGC2%22, SCALPEL_JNI_LIB)) %7B%0A            if (!loadLib(library)) %7B%0A                initialized = false;%0A                logger.log(Level.SEVERE, %22Failed initializing %22 + ScalpelCarver.class.getName() + %22 due to failure loading library: %22 + library);%0A                break;%0A            %7D%0A        %7D%0A        %0A        if (initialized) %7B%0A            logger.log(Level.INFO, ScalpelCarver.class.getName() + %22 JNI initialized successfully. %22);%0A        %7D%0A    %7D%0A%0A
     /**%0A     * i
@@ -2094,37 +2094,85 @@
     private 
-void init() %7B
+boolean loadLib(String id) %7B%0A        boolean success = false;
 %0A        try
@@ -2290,31 +2290,18 @@
 Library(
-SCALPEL_JNI_LIB
+id
 );%0A     
@@ -2303,35 +2303,31 @@
             
-initialized
+success
  = true;%0A   
@@ -2371,41 +2371,8 @@
 ) %7B%0A
-            initialized = false;%0A
     
@@ -2408,35 +2408,30 @@
 ot load 
-%22 + SCALPEL_JNI_LIB
+library %22 + id
  + %22 for
@@ -2588,41 +2588,8 @@
 ) %7B%0A
-            initialized = false;%0A
     
@@ -2629,27 +2629,22 @@
 oad 
-%22 + SCALPEL_JNI_LIB
+library %22 + id
  + %22
@@ -2769,32 +2769,57 @@
 , ex);%0A        %7D
+%0A%0A        return success;
 %0A    %7D%0A%0A    /**%0A
@@ -4166,32 +4166,24 @@
 ;%0A        %7D%0A
-        
 %0A        //b
@@ -4383,17 +4383,16 @@
 sEmpty()
- 
 ) %7B%0A    
@@ -4566,24 +4566,16 @@
 (file);%0A
-        
 %0A       

improve scalpel class loader to load dependant libs first