import java.util.*;
import java.io.*;
import java.text.SimpleDateFormat;
import com.basis.filesystem.*;
import com.basis.filesystem.util.*;
 
/**
* Class used as a utility to display file information.
*
* @version $Revision: 2.78 $
*/
public class FileInfo
{
    /**
    * Private constructor...
    */
    private FileInfo ()
    {
    }
    // Usage information...
    private static void usage ()
    {
        System.err.println("<id> [-h] <file path> ...");
    }
    /**
    * Function for command line file information. This function
    * will open all files specified on the command line (in turn)
    * and display file information.
    *
    * @param p_argv Command line arguments.
    */
    public static void main (String []p_argv)
    {
        // All files calls will go through this ConnectionMgr.
        ConnectionMgr connectionMgr = Filesystem.getConnectionMgr();
        connectionMgr.setUser(System.getProperty("user.name"));
        try
        {
            // Initialize the license connection for the
            // ConnectionMgr. This must be done before
            // any calls are made.
            connectionMgr.initLocalConnection();
        }
        catch (FilesystemException ex)
        {
            // An error occurred. Just print it out and exit.
            ex.printStackTrace();
            System.exit(1);
        }
        // Print header information only?
        boolean headerOnly = false;
        // List of files to get information on.
        List read = new LinkedList();
        // Interpret/read command line arguments.
        try
        {
            for (int i = 0; i < p_argv.length; i++)
            {
                if (p_argv[i].startsWith("-"))
                {
                    if (p_argv[i].equals("-h"))
                    {
                        headerOnly = true;
                    }
                    else
                    {
                        System.err.println("Unknown option: " + p_argv[i]);
                        usage();
                        System.exit(1);
                    }
                }
                else
                {
                    read.add(p_argv[i]);
                }
            }
        }
        catch (Exception ex)
        {
            System.err.println("Error reading options.");
            usage();
            System.exit(1);
        }
        // PrintWriter to display all file information on.
        PrintWriter out = new PrintWriter(System.out);
        // Iterate over the files getting file information.
        Iterator iter = read.iterator();
        while (iter.hasNext())
        {
            String filepath = (String)iter.next();
            FilePosition pos = null;
            try
            {
                // Open the file read-only.
                pos = connectionMgr.open(filepath,true,true);
            }
            catch (FilesystemException ex)
            {    
                out.println("Unable to open file '"
                    + filepath
                    + "': "
                    + ex.getMessage());
                out.flush();
                continue;
            }
            // Print file information.
            printHeader (pos,out);
            out.flush();
            if (!headerOnly)
            {
                // Print file contents.
                printData(pos,out);
                out.flush();
            }
            try
            {
                // Close the file.
                pos.close();
            }
            catch (FilesystemException ex)
            {
                // Ignore...
            }
        }
        out.flush();
    }
    /**
    * Print file header information.
    *
    * @param p_pos <code>FilePosition</code> to print the header for.
    * @param p_out <code>PrintWriter</code> to print information to.
    */
    public static void printHeader (FilePosition p_pos,
        PrintWriter p_out)
    {
        // FID information.
        try
        {
            p_out.println("Filename: '" + p_pos.getFilename() + "'");
            int type = p_pos.getFileType();
            String name;
            switch (type & Filesystem.TYPEMASK)
            {
            case Filesystem.INDEXED_FILE:
                name = "INDEXED";
                break;
            case Filesystem.SERIAL_FILE:
                name = "SERIAL";
                break;
            case Filesystem.DIRECT_FILE:
                name = "DIRECT";
                break;
            case Filesystem.STRING_FILE:
                name = "STRING";
                break;
            case Filesystem.PROGRAM_FILE:
                name = "PROGRAM";
                break;    
            case Filesystem.DIRECTORY_FILE:
                name = "DIRECTORY";
                break;
            case Filesystem.MKEYED_FILE:
                name = "MKEYED";
                break;
            case Filesystem.XKEYED_FILE:
                name = "XKEYED";
                break;
            default:
                name = "UNKNOWN";
                break;
            }
            p_out.println("File type ("
                + String.valueOf(type & Filesystem.TYPEMASK)
                + "): " + name);
            String mod = "";
            int modifier = (type & ~Filesystem.TYPEMASK) & 0xFF;
            switch (modifier)
            {
            case 0:
                mod = "NONE";
                break;
            case Filesystem.MKEYED_64BIT:
                mod = "64 BIT";
                break;
            case Filesystem.MKEYED_4GIG:
                mod = "4 GIG";
                break;
            case Filesystem.MKEYED_TAGRECORD:
                mod = "TAGGED RECORD";
                break;
            case (Filesystem.MKEYED_4GIG | Filesystem.MKEYED_TAGRECORD):
                mod = "TAGGED RECORD 4 GIG";
                break;
            case (Filesystem.MKEYED_64BIT | Filesystem.MKEYED_TAGRECORD):
                mod = "TAGGED RECORD 64 BIT";
                break;
            default:
                mod = "UNKNOWN";
                break;
            }
            p_out.println("MODIFIER ("
                + String.valueOf(modifier)
                + "): " + mod);
            p_out.println("Key size: " + String.valueOf(p_pos.getKeySize()));
            p_out.println("Max number of records: " + String.valueOf(p_pos.getNumberOfRecords()));
            p_out.println("Record size: " + String.valueOf(p_pos.getRecordSize()));
        }
        catch (FilesystemException ex)
        {
            p_out.println("Failed to get FID information for file: " + ex.getMessage());
        }
        // FIN information.
        try
        {
            // Common FIN information.
            p_out.println("File length: " + String.valueOf(p_pos.getLength()));
            SimpleDateFormat cal = new SimpleDateFormat();
            p_out.println("Last modified: " + cal.format(new Date(p_pos.getLastModified())));
            // Getable for every file type.
            p_out.println("Record count: " + String.valueOf(p_pos.getRecordCount()));
            byte []fin = p_pos.getFIN(0);
            // File information dependent on type.
            switch (p_pos.getFileType() & Filesystem.TYPEMASK)
            {
            case Filesystem.INDEXED_FILE:
                p_out.println("NO ADDITIONAL FILE INFORMATION");
                break;
            case Filesystem.SERIAL_FILE:
                {
                    long tmp = ((fin[64] & 0xFFL) << 24)
                        | ((fin[65] & 0xFFL) << 16)
                        | ((fin[66] & 0xFFL) << 8)
                        | (fin[67] & 0xFFL);
                    p_out.println("Next available file index: " + String.valueOf(tmp));
    
                    tmp = ((fin[68] & 0xFFL) << 24)
                        | ((fin[69] & 0xFFL) << 16)
                        | ((fin[70] & 0xFFL) << 8)
                        | (fin[71] & 0xFFL);
                    p_out.println("Number of bytes in file (including header): " + String.valueOf(tmp));
                    tmp = ((fin[72] & 0xFFL) << 8)
                        | (fin[73] & 0xFFL);
                    p_out.println("Number of bytes in last record: " + String.valueOf(tmp));
                }
                break;
            case Filesystem.DIRECT_FILE:
                {
                    long tmp = ((fin[64] & 0xFFL) << 24)
                        | ((fin[65] & 0xFFL) << 16)
                        | ((fin[66] & 0xFFL) << 8)
                        | (fin[67] & 0xFFL);
                    p_out.println("Index of last key removed: " + String.valueOf(tmp));
                    tmp = ((fin[68] & 0xFFL) << 24)
                        | ((fin[69] & 0xFFL) << 16)
                        | ((fin[70] & 0xFFL) << 8)
                        | (fin[71] & 0xFFL);
                    p_out.println("Index of lowest available key: " + String.valueOf(tmp));
                    tmp = ((fin[72] & 0xFFL) << 24)
                        | ((fin[73] & 0xFFL) << 16)
                        | ((fin[74] & 0xFFL) << 8)
                        | (fin[75] & 0xFFL);
                    p_out.println("Index of lowest logical key: " + String.valueOf(tmp));
                    tmp = ((fin[76] & 0xFFL) << 24)
                        | ((fin[77] & 0xFFL) << 16)
                        | ((fin[78] & 0xFFL) << 8)
                        | (fin[79] & 0xFFL);
                    p_out.println("Number of active keys in the file: " + String.valueOf(tmp));
                    tmp = ((fin[80] & 0xFFL) << 24)
                        | ((fin[81] & 0xFFL) << 16)
                        | ((fin[82] & 0xFFL) << 8)
                        | (fin[83] & 0xFFL);
                    p_out.println("Index of highest logical key: " + String.valueOf(tmp));
                }
                break;
            case Filesystem.STRING_FILE:
                p_out.println("NO ADDITIONAL FILE INFORMATION");
                break;
            case Filesystem.PROGRAM_FILE:
                p_out.println("NO ADDITIONAL FILE INFORMATION");
                break;
            case Filesystem.DIRECTORY_FILE:
                p_out.println("NO ADDITIONAL FILE INFORMATION");
                break;
            case Filesystem.MKEYED_FILE:
                {
                    long tmp = ((fin[76] & 0xFFL) << 24)
                        | ((fin[77] & 0xFFL) << 16)
                        | ((fin[78] & 0xFFL) << 8)
                        | (fin[79] & 0xFFL);
                    p_out.println("Number of active keys in the file: " + String.valueOf(tmp));
                    p_out.println("Default KNUM value: " + String.valueOf(fin[84] & 0xFF));
                    if (p_pos.getKeySize() == 0)
                    {
                        List keyDesc = p_pos.getKeyDescriptions();
                        p_out.println("KEYS:");
                        Iterator iter = keyDesc.iterator();
                        while (iter.hasNext())
                        {
                            p_out.println("\t" + String.valueOf(iter.next()));
                        }
                    }
                }    
                break;
            case Filesystem.XKEYED_FILE:
                {
                    long tmp = ((fin[76] & 0xFFL) << 24)
                        | ((fin[77] & 0xFFL) << 16)
                        | ((fin[78] & 0xFFL) << 8)
                        | (fin[79] & 0xFFL);
                    p_out.println("Number of active keys in the file: " + String.valueOf(tmp));
                    p_out.println("Default KNUM value: " + String.valueOf(fin[84] & 0xFF));
                    if (p_pos.getKeySize() == 0)
                    {
                        List keyDesc = p_pos.getKeyDescriptions();
                        p_out.println("KEYS:");
                        Iterator iter = keyDesc.iterator();
                        while (iter.hasNext())
                        {
                            p_out.println("\t" + String.valueOf(iter.next()));
                        }
                    }
                }
                break;
                default:
                    p_out.println("<<UNKNOWN FILE TYPE>>");
                    break;
            }
        }
        catch (FilesystemException ex)
        {
            System.out.println("Failed to get FIN information for file: " + ex.getMessage());
        }
    }
    /**
    * Print file data.
    *
    * @param p_pos <code>FilePosition</code> to print the data for.
    * @param p_out <code>PrintWriter</code> to print information to.
    */
    public static void printData (FilePosition p_pos,PrintWriter p_out)
    {
        p_out.println("FILE DATA:");
        try
        {
            byte [][]key = null;
            byte []record = null;
            // Check for record size and allocate buffer.
            if (p_pos.getRecordSize() > 0)
            {
                record = new byte[p_pos.getRecordSize()];
            }
            else
            {
                record = new byte[100];
            }
            // Check for single-keyed file.
            if (p_pos.getKeySize() > 0)
            {
                key = new byte[1][p_pos.getKeySize()];
            }
            else if (((p_pos.getFileType() & Filesystem.TYPEMASK) == Filesystem.MKEYED_FILE)
                || ((p_pos.getFileType() & Filesystem.TYPEMASK) == Filesystem.XKEYED_FILE))
            {
                // This is a multi-keyed MKEYED or XKEYED file.
                // get KeyDescriptions and the size of each key.
                List keyDesc = p_pos.getKeyDescriptions();
                key = new byte[keyDesc.size()][];
                for (int i = 0; i < key.length; i++)
                {
                    KeyDescription desc = (KeyDescription)keyDesc.get(i);
                    key[i] = new byte[desc.getKeySize()];
                }
            }
            try
            {
                // Iterate over all of the file records.
                while (true)
                {
                    // If this is a keyed file, get all of the keys.
                    if (key != null)
                    {
                        for (int i = 0; i < key.length; i++)
                        {
                            int len = p_pos.getKey(key[i],key[i].length,i);
                            p_out.print("KEY_" + String.valueOf(i) + ": ");
                            printByteArray(key[i],len,p_out);
                        }
                    }
                    // Read the current record and iterate to the next record.
                    if (record == null)
                    {
                        p_pos.read(null,0,1,5,false);
                    }
                    else
                    {
                        int len = p_pos.read(record,record.length,1,5,false);
                        p_out.print("RECORD: ");
                        printByteArray(record,len,p_out);
                    }
                    p_out.println();
                }
            }
            catch (FilesystemEOFException ex)
            {
                // End of iteration...
            }
        }
        catch (FilesystemException ex)
        {
            p_out.println("Failed to get data from file: " + ex.getMessage());
        }
    }
    /**
    * Helper function to print an array of bytes.
    *
    * @param p_bytes Array of bytes to print.
    * @param p_len Length of bytes to print.
    * @param p_out <code>PrintWriter</code> to print bytes to.
    */
    private static void printByteArray (byte []p_bytes, int p_len,PrintWriter p_out)
    {
        p_out.print("[");
        int i = 0;
        for (i = 0; i < (p_len-1); i++)
        {
            p_out.print(String.valueOf(p_bytes[i] & 0xFF) + ", ");
        }
        if (p_len > 0)
        {
            p_out.print(String.valueOf(p_bytes[i] & 0xFF));
        }
        p_out.println("]");
    }
} 
                                                     |