/* XXL: The eXtensible and fleXible Library for data processing Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger Head of the Database Research Group Department of Mathematics and Computer Science University of Marburg Germany This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; If not, see <http://www.gnu.org/licenses/>. http://code.google.com/p/xxl/ */ package xxl.core.io; import java.awt.Container; import java.awt.Dimension; import java.awt.Font; import java.awt.Frame; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.net.URL; import java.util.Enumeration; import java.util.StringTokenizer; import java.util.Vector; import javax.swing.BoxLayout; import javax.swing.JButton; import javax.swing.JComboBox; import javax.swing.JDialog; import javax.swing.JEditorPane; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JSplitPane; import javax.swing.JTable; import javax.swing.JTextArea; import javax.swing.JTextField; import javax.swing.JTextPane; import javax.swing.JTree; import javax.swing.KeyStroke; import javax.swing.ListSelectionModel; import javax.swing.WindowConstants; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import javax.swing.event.TreeExpansionEvent; import javax.swing.event.TreeExpansionListener; import javax.swing.event.TreeModelEvent; import javax.swing.event.TreeModelListener; import javax.swing.event.TreeSelectionEvent; import javax.swing.event.TreeSelectionListener; import javax.swing.table.AbstractTableModel; import javax.swing.text.Style; import javax.swing.text.StyleConstants; import javax.swing.text.StyleContext; import javax.swing.tree.DefaultMutableTreeNode; import javax.swing.tree.DefaultTreeModel; import javax.swing.tree.MutableTreeNode; import javax.swing.tree.TreePath; import javax.swing.tree.TreeSelectionModel; import xxl.core.io.fat.DIR; import xxl.core.io.fat.DirectoryDate; import xxl.core.io.fat.DirectoryTime; import xxl.core.io.fat.ExtendedFile; import xxl.core.io.fat.ExtendedRandomAccessFile; import xxl.core.io.fat.FAT; import xxl.core.io.fat.FATDevice; import xxl.core.io.fat.FileSystem; import xxl.core.io.fat.errors.DirectoryException; import xxl.core.io.fat.errors.WrongFATType; import xxl.core.io.fat.util.StringOperations; import xxl.core.io.raw.NativeRawAccess; import xxl.core.io.raw.RAFRawAccess; import xxl.core.io.raw.RAMRawAccess; import xxl.core.io.raw.RawAccess; import xxl.core.io.raw.RawAccessUtils; import xxl.core.util.XXLSystem; ///////////////////////////////////////////////////////////////// // I didn't split the classes to different files, because this // // class was build for test purposes. So all classes for test- // // ing can be found here. // ///////////////////////////////////////////////////////////////// /** * This class is a bit like the windows-explorer. It can be used to test the functionalty * of the file system implementation. */ public class RawExplorer extends JFrame { /** * Directoryname, where the files are stored. */ protected static String outDir; /** * This file is used to initialize the FileSystem class. All * devices that are listed in that file will be booted. */ protected static File masterBootRecordFile = null; /** * Name of the file. */ protected static String masterBootRecordFileName = "filesystem.txt"; /** * Dummy file for ExtendedRandomAccessFile */ protected static File dummyFile = null; /** * Size of a floppy disk in bytes. */ public static final long DISK_SIZE = 1474560; //Floppy disk in bytes /** * Size of a 100 MB Zip-Disk in bytes. */ public static final long ZIP_DISK_SIZE = 100646912; //Zip-Disk in bytes /** * Indicates a RAF, that is a RandomAccessFile. */ public static final byte RAF = 1; /** * Indicates a RAM, that is a file in memory. */ public static final byte RAM = 2; /** * Indicates a raw access file that can be used on a raw device. */ public static final byte NATIVE = 3; /** * Object of the FileSystem. */ private FileSystem fileSystem; /** * The actual selected device. */ private FATDevice selectedDevice = null; /** * The actual selected path. */ private String actualPath = ""; //only the path /** * The actual selected file name. */ private String actualFileName = null; //only the name /** * The directory tree. */ private DynamicTree deviceTree = new DynamicTree(); /** * The text output area. */ protected JTextArea output; /** * The scroll pane for the text-output-area. */ protected JScrollPane outputScrollPane; /** * The scroll pane for the file table. */ protected JScrollPane fileTableScrollPane; /** * Some operations. */ protected String[] operations = {"createFile", "createDir", "deleteFile", "renameFile", "readFile", "writeStuff"}; /** * The box which contains the supported operations. */ JComboBox operationsBox = new JComboBox(operations); /** * Not used yet. */ JTextField parameter1 = new JTextField(5); /** * Not used yet. */ JTextField parameter2 = new JTextField(5); /** * The file table which lists the informations about the files and directories. */ JTable fileTable; /** * The model of the file table, it's used to manage the informations * stored at the file table. */ FileTableModel fileTableModel; /** * Create an instance of this object. */ public RawExplorer() { outDir = Common.getOutPath(); dummyFile = new File(outDir+"dummyFile"); try { dummyFile.createNewFile(); } catch (IOException e) {} masterBootRecordFile = new File(outDir+masterBootRecordFileName); JMenuBar menuBar; JMenu informationMenu; JMenu fileSystemMenu; JMenu changeFsInfoMenu; JMenu helpMenu; JMenuItem aboutMenuItem, helpMenuItem; JMenuItem copyFileToRawMenu, copyFileFromRawMenu; JMenu formatSubMenu, formatSubMenu2, formatSubMenuFAT12, formatSubMenuFAT16, formatSubMenuFAT32; JMenuItem boot, formatDiskRAF, formatDiskNative, formatZipRAF, formatZipNative, formatFreeFAT12RAF, formatFreeFAT12RAM, formatFreeFAT12Native, formatFreeFAT16RAF, formatFreeFAT16RAM, formatFreeFAT16Native, formatFreeFAT32RAF, formatFreeFAT32RAM, formatFreeFAT32Native, exit, fastFormat; JMenuItem bpbItem, fatItem, fsiItem, rootItem, bootItem, readSectorItem, bpbInfoItem; fileTableModel = new FileTableModel(this); fileTable = new JTable(fileTableModel); setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { if (fileSystem != null) fileSystem.shutDown(); } }); //Add regular components to the window, using the default BorderLayout. output = new JTextArea(); output.setEditable(false); output.setFont(new Font("Courier", Font.PLAIN, 12)); outputScrollPane = new JScrollPane(output); fileTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); ListSelectionModel rowSM = fileTable.getSelectionModel(); rowSM.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { if (e.getValueIsAdjusting()) return; ListSelectionModel lsm = (ListSelectionModel)e.getSource(); if (!lsm.isSelectionEmpty()) { int selectedRow = lsm.getMinSelectionIndex(); //selectedRow is selected actualFileName = (String)fileTable.getValueAt(selectedRow, 0); } } }); fileTableScrollPane = new JScrollPane(fileTable); //Create the menu bar. menuBar = new JMenuBar(); setJMenuBar(menuBar); //Build the first menu. fileSystemMenu = new JMenu("FileSystem"); fileSystemMenu.setMnemonic('F'); fileSystemMenu.getAccessibleContext().setAccessibleDescription( "Boot, format, and other stuff for file system." ); menuBar.add(fileSystemMenu); //a group of JMenuItems boot = new JMenuItem("Boot Device", KeyEvent.VK_B); boot.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_1, ActionEvent.ALT_MASK)); boot.getAccessibleContext().setAccessibleDescription("Boot a device."); boot.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { FATDevice device = bootDevice(); if (device != null) deviceTree.addObject(new NodeInfo(device.getRealDeviceName())); else JOptionPane.showMessageDialog(RawExplorer.this, "Device was not booted."); } catch(Exception ex) { JOptionPane.showMessageDialog(RawExplorer.this, ex); } } }); fileSystemMenu.add(boot); formatSubMenu = new JMenu("Create new device"); formatSubMenu.setMnemonic(KeyEvent.VK_F); fileSystemMenu.add(formatSubMenu); formatDiskRAF = new JMenuItem("Format Disk RAF "); formatDiskRAF.setMnemonic(KeyEvent.VK_D); formatDiskRAF.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { createDeviceDiskRAF(); } catch(Exception ex) { System.out.println(ex); } } }); formatSubMenu.add(formatDiskRAF); formatDiskNative = new JMenuItem("Format Disk Native"); formatDiskNative.setMnemonic(KeyEvent.VK_N); formatDiskNative.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { createDeviceDiskNative(); } catch(Exception ex) { System.out.println(ex); } } }); formatSubMenu.add(formatDiskNative); formatZipRAF = new JMenuItem("Format Zip-Disk RAF"); formatZipRAF.setMnemonic(KeyEvent.VK_M); formatZipRAF.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { createDeviceZipDiskRAF(); } catch(Exception ex) { System.out.println(ex); } } }); formatSubMenu.add(formatZipRAF); formatZipNative = new JMenuItem("Format Zip-Disk Native"); formatZipNative.setMnemonic(KeyEvent.VK_N); formatZipNative.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { createDeviceZipDiskNative(); } catch(Exception ex) { System.out.println(ex); } } }); formatSubMenu.add(formatZipNative); formatSubMenu2 = new JMenu("Format Free Value"); formatSubMenu2.setMnemonic(KeyEvent.VK_O); formatSubMenu.add(formatSubMenu2); formatSubMenuFAT12 = new JMenu("FAT12"); formatSubMenuFAT12.setMnemonic(KeyEvent.VK_F); formatSubMenu2.add(formatSubMenuFAT12); formatSubMenuFAT16 = new JMenu("FAT16"); formatSubMenuFAT12.setMnemonic(KeyEvent.VK_A); formatSubMenu2.add(formatSubMenuFAT16); formatSubMenuFAT32 = new JMenu("FAT32"); formatSubMenuFAT32.setMnemonic(KeyEvent.VK_T); formatSubMenu2.add(formatSubMenuFAT32); formatFreeFAT12RAF = new JMenuItem("RAF"); formatFreeFAT12RAF.setMnemonic(KeyEvent.VK_R); formatFreeFAT12RAF.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { createDeviceRAF(FAT.FAT12); } catch(Exception ex) { System.out.println(ex); } } }); formatSubMenuFAT12.add(formatFreeFAT12RAF); formatFreeFAT12RAM = new JMenuItem("RAM"); formatFreeFAT12RAM.setMnemonic(KeyEvent.VK_A); formatFreeFAT12RAM.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { createDeviceRAM(FAT.FAT12); } catch(Exception ex) { System.out.println(ex); } } }); formatSubMenuFAT12.add(formatFreeFAT12RAM); formatFreeFAT12Native = new JMenuItem("Native"); formatFreeFAT12Native.setMnemonic(KeyEvent.VK_N); formatFreeFAT12Native.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { createDeviceNative(FAT.FAT12); } catch(Exception ex) { System.out.println(ex); } } }); formatSubMenuFAT12.add(formatFreeFAT12Native); formatFreeFAT16RAF = new JMenuItem("RAF"); formatFreeFAT16RAF.setMnemonic(KeyEvent.VK_R); formatFreeFAT16RAF.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { createDeviceRAF(FAT.FAT16); } catch(Exception ex) { System.out.println(ex); } } }); formatSubMenuFAT16.add(formatFreeFAT16RAF); formatFreeFAT16RAM = new JMenuItem("RAM"); formatFreeFAT16RAM.setMnemonic(KeyEvent.VK_A); formatFreeFAT16RAM.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { createDeviceRAM(FAT.FAT16); } catch(Exception ex) { System.out.println(ex); } } }); formatSubMenuFAT16.add(formatFreeFAT16RAM); formatFreeFAT16Native = new JMenuItem("Native"); formatFreeFAT16Native.setMnemonic(KeyEvent.VK_N); formatFreeFAT16Native.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { createDeviceNative(FAT.FAT16); } catch(Exception ex) { System.out.println(ex); } } }); formatSubMenuFAT16.add(formatFreeFAT16Native); formatFreeFAT32RAF = new JMenuItem("RAF"); formatFreeFAT32RAF.setMnemonic(KeyEvent.VK_R); formatFreeFAT32RAF.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { createDeviceRAF(FAT.FAT32); } catch(Exception ex) { System.out.println(ex); } } }); formatSubMenuFAT32.add(formatFreeFAT32RAF); formatFreeFAT32RAM = new JMenuItem("RAM"); formatFreeFAT32RAM.setMnemonic(KeyEvent.VK_A); formatFreeFAT32RAM.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { createDeviceRAM(FAT.FAT32); } catch(Exception ex) { System.out.println(ex); } } }); formatSubMenuFAT32.add(formatFreeFAT32RAM); formatFreeFAT32Native = new JMenuItem("Native"); formatFreeFAT32Native.setMnemonic(KeyEvent.VK_N); formatFreeFAT32Native.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { createDeviceNative(FAT.FAT32); } catch(Exception ex) { System.out.println(ex); } } }); formatSubMenuFAT32.add(formatFreeFAT32Native); copyFileToRawMenu = new JMenuItem("Copy file to raw", KeyEvent.VK_8); copyFileToRawMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_8, ActionEvent.ALT_MASK)); copyFileToRawMenu.getAccessibleContext().setAccessibleDescription("Copy file from 'normal' file system to this file system implementation"); copyFileToRawMenu.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { copyFileToRaw(); } catch(Exception ex) { JOptionPane.showMessageDialog(RawExplorer.this, ex); } } }); fileSystemMenu.add(copyFileToRawMenu); copyFileFromRawMenu = new JMenuItem("Copy file from raw", KeyEvent.VK_9); copyFileFromRawMenu.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_9, ActionEvent.ALT_MASK)); copyFileFromRawMenu.getAccessibleContext().setAccessibleDescription("Copy file from this file system implementation to 'normal' file system"); copyFileFromRawMenu.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { try { copyFileFromRaw(); } catch(Exception ex) { JOptionPane.showMessageDialog(RawExplorer.this, ex); } } }); fileSystemMenu.add(copyFileFromRawMenu); fastFormat = new JMenuItem("Fast format device", KeyEvent.VK_F); fastFormat.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_9, ActionEvent.ALT_MASK)); fastFormat.getAccessibleContext().setAccessibleDescription("Fast format the actual device."); fastFormat.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { fastFormat(); } }); fileSystemMenu.add(fastFormat); exit = new JMenuItem("Exit"); exit.setMnemonic(KeyEvent.VK_X); exit.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (fileSystem != null) fileSystem.shutDown(); dispose(); } }); fileSystemMenu.add(exit); //Build second menu in the menu bar. informationMenu = new JMenu("Informations"); informationMenu.setMnemonic('I'); informationMenu.getAccessibleContext().setAccessibleDescription("This menu does nothing"); menuBar.add(informationMenu); bpbItem = new JMenuItem("Print BPB"); bpbItem.setMnemonic('B'); bpbItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_2, ActionEvent.ALT_MASK)); bpbItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { printBPB(); } }); informationMenu.add(bpbItem); fatItem = new JMenuItem("Print FAT"); fatItem.setMnemonic('F'); fatItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_5, ActionEvent.ALT_MASK)); fatItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { printFAT(); } }); informationMenu.add(fatItem); fsiItem = new JMenuItem("Print FSI"); fsiItem.setMnemonic('S'); fsiItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_6, ActionEvent.ALT_MASK)); fsiItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { printFSI(); } }); informationMenu.add(fsiItem); rootItem = new JMenuItem("Print Root"); rootItem.setMnemonic('r'); rootItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_7, ActionEvent.ALT_MASK)); rootItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { printRoot(); } }); informationMenu.add(rootItem); bootItem = new JMenuItem("Show filesystem"); bootItem.setMnemonic('S'); bootItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_5, ActionEvent.ALT_MASK)); bootItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { printFSInfo(); } }); informationMenu.add(bootItem); readSectorItem = new JMenuItem("Read sectors"); readSectorItem.setMnemonic('S'); readSectorItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_8, ActionEvent.ALT_MASK)); readSectorItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { printSectors(); } }); informationMenu.add(readSectorItem); bpbInfoItem = new JMenuItem("Print BPB-info"); bpbInfoItem.setMnemonic('I'); bpbInfoItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_9, ActionEvent.ALT_MASK)); bpbInfoItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { printBPBInfo(); } }); informationMenu.add(bpbInfoItem); operationsBox.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { if (selectedDevice != null) { String selectedItem = (String)operationsBox.getSelectedItem(); if (selectedItem.equals("createFile")) { createFile(); } else if (selectedItem.equals("createDir")) { createDirectory(); } else if (selectedItem.equals("deleteFile")) { delete(); } else if (selectedItem.equals("renameFile")) { rename(); } else if (selectedItem.equals("readFile")) { readFile(); } else if (selectedItem.equals("writeStuff")) { writeStuff(); } } else System.out.println("selectedDeviceName null"); } }); menuBar.add(operationsBox); //Build fourth menu in the menu bar. changeFsInfoMenu = new JMenu("Change filesystem"); changeFsInfoMenu.setMnemonic('C'); changeFsInfoMenu.getAccessibleContext().setAccessibleDescription("Can be used to manipulate the filesystem file."); JMenuItem changeFsInfoItem = new JMenuItem("change"); changeFsInfoItem.setMnemonic('a'); changeFsInfoItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { //getContentPane().add(new BootFileManipulator()); JFrame frame = new BootFileManipulator(); frame.setVisible(true); } }); changeFsInfoMenu.add(changeFsInfoItem); menuBar.add(changeFsInfoMenu); //Build fifth menu in the menu bar. helpMenu = new JMenu("Help"); helpMenu.setMnemonic('H'); helpMenu.getAccessibleContext().setAccessibleDescription("Get some more infos."); helpMenuItem = new JMenuItem("help"); helpMenuItem.setMnemonic('e'); helpMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JFrame frame = new HelpFrame(); frame.setVisible(true); } }); helpMenu.add(helpMenuItem); aboutMenuItem = new JMenuItem("about"); aboutMenuItem.setMnemonic('a'); aboutMenuItem.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { JFrame frame = new AboutFrame(); frame.setVisible(true); } }); helpMenu.add(aboutMenuItem); menuBar.add(helpMenu); menuBar.add(javax.swing.Box.createHorizontalGlue()); menuBar.add(javax.swing.Box.createHorizontalGlue()); //tree and split panes //Add the scroll panes to a split pane. JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); //add the device tree to the panel splitPane.setTopComponent(deviceTree); JSplitPane splitPane2 = new JSplitPane(JSplitPane.VERTICAL_SPLIT); splitPane2.setTopComponent(fileTableScrollPane); splitPane2.setBottomComponent(outputScrollPane); splitPane.setBottomComponent(splitPane2); splitPane.setDividerLocation(100); splitPane.setPreferredSize(new Dimension(500, 300)); //Add the split pane to this frame getContentPane().add(splitPane); //boot file system fileSystem = new FileSystem(outDir+masterBootRecordFileName, System.out, dummyFile); //add all booted devices to the deviceTree java.util.List devices = fileSystem.getAllDevices(); if (devices != null) { for (int i=0; i < devices.size(); i++) { FATDevice device = ((FileSystem.DeviceInformation)devices.get(i)).getDevice(); String str = device.getRealDeviceName(); deviceTree.addObject(new NodeInfo(str)); } } else System.out.println("No devices"); } //end constructor /** * Call to a dialog with the given string as text at the dialog. * @param text to print at the dialog. * @return the result of the dialog. */ protected String callDialog(String text) { CustomDialog customDialog = new CustomDialog(this, text); customDialog.pack(); customDialog.setLocationRelativeTo(this); customDialog.setVisible(true); return customDialog.getValidatedText(); } /** * This class represents the about frame. */ private class AboutFrame extends JFrame { /**New line seperator*/ private String newline = System.getProperty("line.separator"); /**About frame*/ public AboutFrame() { super("About RawExplorer"); Container contentPane = getContentPane(); JTextPane textPane = new JTextPane(); textPane.setEditable(false); String[] initString = { "\tRawExplorer Version 1.0." + newline+newline, //bold "This program was made in the context of an advanced practical training ",//regular "at the computer science faculty of the Philipps University of Marburg. Copyright 2002."+newline+newline,//regular "Leadership:"+newline, //bold "\tProf. Dr. Bernhard Seeger"+newline, //italic "\tAssistant Martin Schneider."+newline,//italic "Programming:"+newline, //bold "\tMarcus Klein (FAT-System)"+newline, //italic "\tHans Schwarzbach (raw access)" //italic }; String[] initStyles = { "bold", "regular", "regular", "bold", "italic", "italic", "bold", "italic", "italic" }; initStylesForTextPane(textPane); javax.swing.text.Document doc = textPane.getDocument(); try { for (int i=0; i < initString.length; i++) { doc.insertString(doc.getLength(), initString[i], textPane.getStyle(initStyles[i])); } } catch (javax.swing.text.BadLocationException ble) { System.err.println("Couldn't insert initial text."); } contentPane.add(textPane); setSize(300,260); } /**Inits the styles for the text panel * @param textPane the panel.*/ protected void initStylesForTextPane(JTextPane textPane) { //Initialize some styles Style def = StyleContext.getDefaultStyleContext(). getStyle(StyleContext.DEFAULT_STYLE); Style regular = textPane.addStyle("regular", def); StyleConstants.setFontFamily(def, "SansSerif"); Style s = textPane.addStyle("italic", regular); StyleConstants.setItalic(s, true); s = textPane.addStyle("bold", regular); StyleConstants.setBold(s, true); s = textPane.addStyle("small", regular); StyleConstants.setFontSize(s, 10); s = textPane.addStyle("large", regular); StyleConstants.setFontSize(s, 16); } } //end about frame /** * This class represents the help frame. */ private class HelpFrame extends JFrame { /**The name of the help file.*/ String helpFile = "help.html"; /**The path of the help file.*/ String helpPath = "applications" + System.getProperty("file.separator") + "release" + System.getProperty("file.separator") + "io" + System.getProperty("file.separator"); /**Creates the help frame*/ public HelpFrame() { super("Help"); Container contentPane = getContentPane(); JEditorPane editorPane = new JEditorPane(); editorPane.setEditable(false); String s = null; try { s = "file:" + System.getProperty("user.dir") + System.getProperty("file.separator") + helpPath + helpFile; URL helpURL = new URL(s); try { editorPane.setPage(helpURL); } catch (IOException e) { System.err.println("Attempted to read a bad URL: " + helpURL); } } catch (Exception e) { System.err.println("Couldn't create help URL: " + s); } JScrollPane scrollPane = new JScrollPane(editorPane); contentPane.add(scrollPane); setSize(300,260); } //end constructor } //end inner class HelpFrame /** * This class may be used to manipulate the content of the boot-file. * That is the file which contains informations about the devices * created by the file system. */ private class BootFileManipulator extends JFrame { /** * The name of the file where all bootable devices are listed. */ String bootFileName = "fsInfo.txt"; /** * Represents a table model. */ class BootFileTableModel extends AbstractTableModel { /** * The names of the columns. */ protected final String[] columnNames = {"Name", "Size", "Type"}; /** * Contains the informations of the rows of the boot-file-table. * Each row is represented by a RowNode which contains the * different informations for one line. */ protected Vector rowData = new Vector(); /** * Contains the informations to show in the boot-file-table. */ class RowNode { /** * The name of the file. */ String name; /** * The size of the device. */ String size; /** * The type is either "RAF", "RAM", or "NATIVE". */ String type; /** * Set a new name. * @param name the new name. */ void setName(String name) { this.name = name; } /** * Set a new size. * @param size the new size. */ void setSize(String size) { this.size = size; } /** * Set the type. * @param type the type. */ void setType(String type) { this.type = type; } } /** * Create an instance of this object. */ public BootFileTableModel() { } /** * Return the number of columns. * @return the number of columns. */ public int getColumnCount() { return columnNames.length; } /** * Return the number of rows. * @return the number of rows. */ public int getRowCount() { return rowData.size(); } /** * Return the column name of column col. * @param col the column number. * @return the column name of colum col. */ public String getColumnName(int col) { return columnNames[col]; } /** * Return the content of the file table at (row, col). * @param row the row. * @param col the column. * @return the content of the file table at (row, col). */ public Object getValueAt(int row, int col) { if (row < 0 || row >= rowData.size()) return null; RowNode node = (RowNode)rowData.get(row); Object obj; switch (col) { case 0 : {obj = node.name; break;} case 1 : {obj = node.size; break;} case 2 : {obj = node.type; break;} default : {obj = "null";} } return obj; } /** * Return the class at column c. * @param c the column number. * @return the class. */ public Class getColumnClass(int c) { return getValueAt(0, c).getClass(); } /** * Return if the file table cell at (row, col) is editable. * @param row the row. * @param col the column. * @return true if the file table cell[row][col] is editable; otherwise false. */ public boolean isCellEditable(int row, int col) { //Note that the data/cell address is constant, //no matter where the cell appears onscreen. if (col < 2) return false; else return true; } /** * Remove all content of the boot-file-table except the column names. */ public void clear() { for (int i=0; i < columnNames.length; i++) rowData.clear(); } /** * Add a new row at the end of the file table. * @param line contains the informations that should stored at the new row. */ public void addRow(String line) { int row = getRowCount(); StringTokenizer st = new StringTokenizer(line, "\t"); for (int i=0; i < columnNames.length; i++) { String str = "null"; if (st.hasMoreTokens()) str = st.nextToken(); setValueAt(str, row, i); } } /** * Set the content of cell (row, col) to the given value. * @param value the new content. The value must be a ExtendedFile object. * @param row the row. * @param col the column. */ public void setValueAt(Object value, int row, int col) { RowNode node; if (rowData.size() <= row) node = new RowNode(); else node = (RowNode)rowData.get(row); if (col == 0) node.setName((String)value); else if (col == 1) node.setSize((String)value); else if (col == 2) node.setType((String)value); if (rowData.size() <= row) rowData.add(node); } /**Removes a row from the data * @param rowNumber the number of the row.*/ public void removeRow(int rowNumber) { if (rowNumber < 0 || rowNumber >= rowData.size()) return; rowData.remove(rowNumber); } } //end class BootFileTableModel /** * Create an instance of this object. */ public BootFileManipulator() { super("Boot file manipulator"); Container contentPane = getContentPane(); JLabel label = new JLabel("Content of the file "+RawExplorer.masterBootRecordFileName); BoxLayout layout = new BoxLayout(contentPane , BoxLayout.Y_AXIS); final BootFileTableModel bootFileTableModel = new BootFileTableModel(); final JTable bootFileTable = new JTable(bootFileTableModel); String[] lines = FileSystem.getBootFileContent(outDir+masterBootRecordFileName); for (int i=0; i < lines.length; i++) bootFileTableModel.addRow(lines[i]); JButton clearButton = new JButton("clear selected line"); clearButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { int selectedRow = bootFileTable.getSelectedRow(); String deviceName = (String)bootFileTableModel.getValueAt(selectedRow, 0); if (FileSystem.removeLine(deviceName,outDir+masterBootRecordFileName)) bootFileTableModel.removeRow(selectedRow); bootFileTableModel.fireTableDataChanged(); } }); contentPane.setLayout(layout); contentPane.add(label); contentPane.add(new JScrollPane(bootFileTable)); contentPane.add(clearButton); setSize(200,300); } } //end inner class BootFileManipulator /** * Instances of this class represents nodes of the file tree. */ private class NodeInfo { /** * The string shown at the node. */ public String message; /** * A file object which makes it possible to access * informations of the directory represented by this node. */ ExtendedFile file = null; /** * Create an instance of this object. * @param message the text shown at the node. */ public NodeInfo(String message) { this.message = message; } /** * Create an instance of this object. * @param message the text shoen at the node. * @param file the file object stored at this node. */ public NodeInfo(String message, ExtendedFile file) { this.message = message; this.file = file; } /** * Set a new file object. * @param file the new file. */ public void setFile(ExtendedFile file) { this.file = file; } /** * Return the file object. * @return the file object. */ public ExtendedFile getFile() { return file; } /** * Remove the file object from the node. */ public void removeFile() { file = null; } /** * Print the message. * @return the message of this node. */ public String toString() { return message; } } //end inner class NodeInfo /** * A dialog for user interaction. */ class CustomDialog extends JDialog { /** * The typed text. */ private String typedText = null; /** * The option pane. */ private JOptionPane optionPane; /** * Create an instance of this object. * @param aFrame the parent frame. * @param message the text that is shown at the dialog. */ public CustomDialog(Frame aFrame, String message) { super(aFrame, true); setTitle("Question!"); final JTextField textField = new JTextField(10); Object[] array = new Object[2]; array[0] = message; array[1] = textField; final String btnString1 = "Enter"; final String btnString2 = "Cancel"; Object[] options = {btnString1, btnString2}; optionPane = new JOptionPane( array, JOptionPane.QUESTION_MESSAGE, JOptionPane.YES_NO_OPTION, null, options, options[0]); setContentPane(optionPane); setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { optionPane.setValue(new Integer(JOptionPane.CLOSED_OPTION)); } }); textField.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { optionPane.setValue(btnString1); } }); optionPane.addPropertyChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent e) { String prop = e.getPropertyName(); if (isVisible() && (e.getSource() == optionPane) && (prop.equals(JOptionPane.VALUE_PROPERTY) || prop.equals(JOptionPane.INPUT_VALUE_PROPERTY))) { Object value = optionPane.getValue(); if (value == JOptionPane.UNINITIALIZED_VALUE) { //ignore reset return; } // Reset the JOptionPane's value. // If you don't do this, then if the user // presses the same button next time, no // property change event will be fired. optionPane.setValue(JOptionPane.UNINITIALIZED_VALUE); if (value.equals(btnString1)) { typedText = textField.getText(); if (!typedText.equals("")) setVisible(false); else { JOptionPane.showMessageDialog( CustomDialog.this, "Please enter a value or name.", "Warning.", JOptionPane.ERROR_MESSAGE); typedText = null; } } else { // user closed dialog or clicked cancel setVisible(false); typedText = null; } } } }); } //end constructor /** * Return the typed text. * @return the typed text. */ public String getValidatedText() { return typedText; } } //end inner class XXDialogXX /** * Create a RAF device of the given fat type. * @param fatType the type of FAT for the device. */ public void createDeviceRAF(byte fatType) { String name = callDialog("Please enter the name of the device"); if (name == null) return; else if (name.equals("")) { JOptionPane.showMessageDialog(this, "Wrong value. Device will not be created."); return; } long numberOfSectors = 0; String lengthString = callDialog("Please enter the number of sectors that\nshould be used for the device"); if (lengthString == null) return; else if (lengthString.equals("")) { JOptionPane.showMessageDialog(this, "Wrong value. Device will not be created."); return; } try { numberOfSectors = (new Long(lengthString)).longValue(); } catch (Exception e) { JOptionPane.showMessageDialog(this, "Wrong value. Device will not be created."); return; } if (RawAccessUtils.createFileForRaw(name, numberOfSectors)) { RawAccess r = new RAFRawAccess(name); createDevice(name, fatType, r); } } /** * Create a RAM device of the given fat type. * @param fatType the type of fat for the device. */ public void createDeviceRAM(byte fatType) { String name = callDialog("Please enter the name of the device"); if (name == null) { return; } else if (name.equals("")) { JOptionPane.showMessageDialog(this, "Wrong value. Device will not be created."); return; } long numberOfSectors = 0; String lengthString = callDialog("Please enter the number of sectors that\nshould be used for the device"); if (lengthString == null) { return; } else if (lengthString.equals("")) { JOptionPane.showMessageDialog(this, "Wrong value. Device will not be created."); return; } try { numberOfSectors = (new Long(lengthString)).longValue(); System.out.println("RawExplorer numberOfSectors "+numberOfSectors); } catch (Exception e) { JOptionPane.showMessageDialog(this, "Wrong value. Device will not be created."); return; } createDevice(name, fatType, new RAMRawAccess(numberOfSectors)); } /** * Create a RAF disk device */ public void createDeviceDiskRAF() { String name = callDialog("Please enter the name of the device"); if (name == null) { return; } else if (name.equals("")) { JOptionPane.showMessageDialog(this, "Wrong value. Device will not be created."); return; } if (RawAccessUtils.createFileForRaw(name, DISK_SIZE/512)) createDevice(name, FAT.FAT12, new RAFRawAccess(name)); else JOptionPane.showMessageDialog(this, "Couldn't create RandomAccessFile.\nDevice will not be created."); } /** * Create a native disk device. */ public void createDeviceDiskNative() { String name = callDialog("Please enter the name of the device"); if (name == null) { return; } else if (name.equals("")) { JOptionPane.showMessageDialog(this, "Wrong value. Device will not be created."); return; } createDevice(name, FAT.FAT12, new NativeRawAccess(name)); } /** * Create a RAF zip-disk device. */ public void createDeviceZipDiskRAF() { String name = callDialog("Please enter the name of the device"); if (name == null) { return; } else if (name.equals("")) { JOptionPane.showMessageDialog(this, "Wrong value. Device will not be created."); return; } if (RawAccessUtils.createFileForRaw(name, ZIP_DISK_SIZE/512)) createDevice(name, FAT.FAT16, new RAFRawAccess(name)); else JOptionPane.showMessageDialog(this, "Couldn't create RandomAccessFile. Device will not be created."); } /** * Create a native zip-disk device. */ public void createDeviceZipDiskNative() { String name = callDialog("Please enter the name of the device"); if (name == null) { return; } else if (name.equals("")) { JOptionPane.showMessageDialog(this, "Wrong value. Device will not be created."); return; } createDevice(name, FAT.FAT16, new NativeRawAccess(name)); } /** * Create a native device of the given fat type. * @param fatType the type of fat for the device. */ public void createDeviceNative(byte fatType) { String name = callDialog("Please enter the name of the device.\nFor unix: /dev/fd0\nFor win32 \\\\.\\a:"); if (name == null) { return; } else if (name.equals("")) { JOptionPane.showMessageDialog(this, "Wrong value. Device will not be created."); return; } createDevice(name, fatType, new NativeRawAccess(name)); } /** * Create a device of the given naem, fat typeand with the given * rawAccess. * @param name the name of the device. * @param fatType the type of fat for the device. * @param rawAccess the RawAccess object. */ public void createDevice(String name, byte fatType, RawAccess rawAccess) { if (rawAccess instanceof NativeRawAccess) { int res = JOptionPane.showConfirmDialog(this, "WARNING: You will lose all\n informations from device: "+name, "Important", JOptionPane.YES_NO_OPTION); if (res == JOptionPane.NO_OPTION) return; } //create the device with the FileSystem Object if (fileSystem == null) fileSystem = new FileSystem(outDir+masterBootRecordFileName, System.out, dummyFile); try { FATDevice device = fileSystem.initialize(name, rawAccess, fatType, FileSystem.FORMAT); //insert the device object in the device-tree deviceTree.addObject(deviceTree.getRoot(), new NodeInfo(device.getRealDeviceName())); } catch (Exception e) { JOptionPane.showMessageDialog(this, e); return; } } //end createDevice(String name, byte fatType, RawAccess rawAccess) /** * Copy a file from the 'original' file system to this implementated file * system. */ protected void copyFileToRaw() { if (selectedDevice == null) { JOptionPane.showMessageDialog(this, "No device selected."); return; } JFileChooser fileChooser = new JFileChooser(); fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); int result = fileChooser.showOpenDialog(this); if (result == JFileChooser.APPROVE_OPTION) { File file = fileChooser.getSelectedFile(); System.out.println("file: "+file.getAbsolutePath()); if (file.isDirectory()) { String callResult = callDialog("Please enter the destination directory."); if (callResult == null) return; else if (callResult.equals("")) { JOptionPane.showMessageDialog(this, "Wrong value. No file will be copied."); return; } String destinationFolder = callResult; copyDirectoryToRaw(file, destinationFolder); } else { String destinationName = actualPath + System.getProperty("file.separator") + file.getName(); try { selectedDevice.copyFileToRAW(file, destinationName); } catch (DirectoryException de) { JOptionPane.showMessageDialog(this, de); } catch (FileNotFoundException ffe ) { JOptionPane.showMessageDialog(this, ffe); } catch (IOException io) { JOptionPane.showMessageDialog(this, io); } } updateFileTable(deviceTree.getSelectedPath()); } } //end copyFileToRaw() /**Copies a directory from the 'original' file system to this implementated file * system. * @param file the file object. * @param destinationFolder the destination folder. * */ protected void copyDirectoryToRaw(File file, String destinationFolder) { try { File[] dirFiles = file.listFiles(); for (int i=0; i < dirFiles.length; i++) { if (dirFiles[i].isDirectory()) //directory { String newDir = destinationFolder + System.getProperty("file.separator") + dirFiles[i].getName(); System.out.println("will create directory '"+newDir+"'"); ExtendedFile ef = selectedDevice.getFile(newDir); if (!ef.exists()) { if (!ef.mkdir()) JOptionPane.showMessageDialog(this, "Couldn't create the directory:\n "+ef.getAbsolutePath()); } copyDirectoryToRaw(dirFiles[i], newDir); } else //file { selectedDevice.copyFileToRAW( dirFiles[i], destinationFolder + System.getProperty("file.separator") + dirFiles[i].getName() ); } } } catch (DirectoryException de) { JOptionPane.showMessageDialog(this, de); } catch (FileNotFoundException ffe ) { JOptionPane.showMessageDialog(this, ffe); } catch (IOException io) { JOptionPane.showMessageDialog(this, io); } } //end copy DirectoryToRaw /** * Copy a file from the implementades file system to the 'original' file * system. A dialog will ask for the name and raw type. */ public void copyFileFromRaw() { String sourceName; if (actualPath == null || actualPath.equals("")) { String result = callDialog("Please enter the source name."); if (result == null) return; else if (result.equals("")) { JOptionPane.showMessageDialog(this, "Wrong value. No file will be copied."); return; } sourceName = result; } else sourceName = actualPath + System.getProperty("file.separator") + actualFileName; JFileChooser fileChooser = new JFileChooser(actualFileName); fileChooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); int result = fileChooser.showSaveDialog(this); if (result == JFileChooser.APPROVE_OPTION) { File destinationFile = fileChooser.getSelectedFile(); try { selectedDevice.copyFileToOriginalFileSystem(sourceName, destinationFile); } catch (Exception e) { JOptionPane.showMessageDialog(this, e); } } } //end copyFileFromRaw /** * This method can only be used, when the device formated before. * It will clear the FAT-structure but don't override the bad * cluster marks, it will also reinitialize the root-directory. * After the call of this method, the device should look like * a fresh formated device. */ protected void fastFormat() { if (selectedDevice != null) { selectedDevice.fastFormat(); updateFileTable(deviceTree.getSelectedPath()); } else JOptionPane.showMessageDialog(this, "No device selected."); } /** * Create a file. The name is asked by a dialog. The file will be created at the actual * selected device and directory. */ private void createFile() { String tmp = actualPath; if (!tmp.endsWith(System.getProperty("file.separator"))) tmp = tmp + System.getProperty("file.separator"); String result = callDialog("Please enter the name."); if (result == null) { return; } else if (result.equals("")) { JOptionPane.showMessageDialog(this, "No name specified. File will not be created."); return; } tmp += result; ExtendedFile ef = selectedDevice.getFile(tmp); try{ ef.createNewFile(); } catch (Exception e) { e.printStackTrace(); } updateFileTable(deviceTree.getSelectedPath()); } //end createFile() /** * Create a directory. The name will be asked by a dialog. The directory will be * created at the seletced device and directory. */ public void createDirectory() { String tmp = actualPath; if (!tmp.endsWith(System.getProperty("file.separator"))) tmp = tmp + System.getProperty("file.separator"); String result = callDialog("Please enter the name."); if (result == null) { return; } else if (result.equals("")) { JOptionPane.showMessageDialog(this, "No name specified. Directory will not be created."); return; } tmp += result; ExtendedFile ef = selectedDevice.getFile(tmp); if (ef.mkdir()) JOptionPane.showMessageDialog(this, "Creation of directory was successfull."); else JOptionPane.showMessageDialog(this, "Creation of directory failed."); updateFileTable(deviceTree.getSelectedPath()); } //end createDirectory /** * Delete the actual selected file or directory. If no file or directory * is selected a dialog will ask for the name. */ public void delete() { int row = fileTable.getSelectedRow(); boolean isDir = fileTableModel.isDirectory(row); String tmp = actualPath; if (!tmp.endsWith(System.getProperty("file.separator"))) tmp = tmp + System.getProperty("file.separator"); if (row != -1) { if (actualFileName != null) tmp += actualFileName; else { String result = callDialog("Please enter the name of the file\nthat should be deleted."); if (result == null) { return; } else if (result.equals("")) { JOptionPane.showMessageDialog(this, "No name specified. Delete will not be done."); return; } tmp += result; } } int res = JOptionPane.showConfirmDialog(this, "WARNING: You will delete '"+tmp+"'.", "Important", JOptionPane.YES_NO_OPTION); if (res == JOptionPane.NO_OPTION) return; ExtendedFile ef = selectedDevice.getFile(tmp); if (ef.delete()) //delete was successful { System.out.println("delete was successful."); //in case of a directory remove it also from the file tree if (isDir) { deviceTree.removeNode(selectedDevice, tmp); } } else System.out.println("delete wasn't successful"); updateFileTable(deviceTree.getSelectedPath()); } //end delete() /** * Rename the actual selected file or directory. If no file or directory * is selected a dialog will ask for the name. */ public void rename() { int row = fileTable.getSelectedRow(); boolean isDir = fileTableModel.isDirectory(row); String tmp = actualPath; if (!tmp.endsWith(System.getProperty("file.separator"))) tmp = tmp + System.getProperty("file.separator"); if (row != -1) { if (actualFileName != null) tmp += actualFileName; else { String result = callDialog("Please enter the name of the file\nthat should be renamed."); if (result == null) { return; } else if (result.equals("")) { JOptionPane.showMessageDialog(this, "No name specified. Renaming will not be done."); return; } tmp += result; } } String destinationName = callDialog("Type the new name (inclusive path)."); if (destinationName == null) return; else if (destinationName.equals("")) { JOptionPane.showMessageDialog(this, "No destination name specified.\nRenaming will not be done."); return; } int res = JOptionPane.showConfirmDialog(this, "WARNING: You will rename '"+tmp+"' to\n'"+destinationName+"'.", "Important", JOptionPane.YES_NO_OPTION); if (res == JOptionPane.NO_OPTION) return; if (selectedDevice == null) { JOptionPane.showMessageDialog(this, "Please select a device first."); return; } ExtendedFile ef = selectedDevice.getFile(tmp); if (ef.renameTo(selectedDevice.getFile(destinationName))) //rename was successful { System.out.println("rename was successful"); //in case of a directory remove it also from the file tree if (isDir) { deviceTree.removeNode(selectedDevice, tmp); } } else System.out.println("rename wasn't successful"); updateFileTable(deviceTree.getSelectedPath()); } //end rename() /** * Boot a device. The name is asked by a dialog. * @return a FATDevice. * @throws Exception */ public FATDevice bootDevice() throws Exception { String deviceName = callDialog("Please enter name of device."); if (deviceName == null) { return null; } else if (deviceName.equals("")) { JOptionPane.showMessageDialog(this, "Wrong value. Device will not be booted."); return null; } String rawType = callDialog("Please enter name raw access type.\n RAF, RAM, or NATIVE."); if (rawType == null) return null; RawAccess ra = null; if (rawType.equals("RAM")) { try { String result = callDialog("Please enter the number of blocks."); if (result == null) return null; else if (result.equals("")) { JOptionPane.showMessageDialog(this, "Wrong value. Device will not be booted."); return null; } long numBlocks = (new Long(result)).longValue(); ra = new RAMRawAccess(numBlocks); } catch (Exception e) { JOptionPane.showMessageDialog(this, "Wrong value. Device will not be booted."); return null; } } else if (rawType.equals("NATIVE")) ra = new NativeRawAccess(deviceName); else if (rawType.equals("RAF")) ra = new RAFRawAccess(deviceName); else { JOptionPane.showMessageDialog(this, "Wrong value. Device will not be booted."); return null; } if (fileSystem == null) fileSystem = new FileSystem(outDir+masterBootRecordFileName, System.out, dummyFile); return fileSystem.initialize(deviceName, ra, FAT.UNKNOWN_FAT, FileSystem.BOOT); } //end bootDevice() /** * Read the content of the selected file to the text area. If no file is selected * a dialog asks one. */ private void readFile() { String tmp = actualPath; if (!tmp.endsWith(System.getProperty("file.separator"))) tmp = tmp + System.getProperty("file.separator"); if (actualFileName != null) tmp += actualFileName; else { String result = callDialog("Please enter the name of the file\nthat should be read."); if (result == null) { return; } else if (result.equals("")) { JOptionPane.showMessageDialog(this, "Wrong value. File will not be read."); return; } tmp += result; } try { ExtendedRandomAccessFile eraf = selectedDevice.getRandomAccessFile(tmp, "rw"); eraf.seek(0); String result = ""; int read; byte[] buffer = new byte[512]; for (;;) { read = eraf.read(buffer); if (read == -1) break; result += new String(buffer, 0, read); } output.setText(result); eraf.close(); } catch (DirectoryException ex) { System.out.println(ex); } catch (IOException io) { System.out.println(io); } //end try } //end readFile() /** * Write some characters at the beginning of the selected file. * If no file is selected, a dialog asks a file name. */ private void writeStuff() { String tmp = actualPath; if (!tmp.endsWith(System.getProperty("file.separator"))) tmp = tmp + System.getProperty("file.separator"); if (actualFileName != null) tmp += actualFileName; else { String result = callDialog("Please enter the name."); if (result == null) return; else if (result.equals("")) { JOptionPane.showMessageDialog(this, "Wrong value. Stuff will not be written."); return; } tmp += result; } try { ExtendedRandomAccessFile eraf = selectedDevice.getRandomAccessFile(tmp, "rw"); eraf.seek(0); String text = ""; for (int k=0; k < 25; k++) { for (int i=0; i < 23; i++) eraf.write(97+k); eraf.write(13); //cr eraf.write(10); //lf } output.setText(text); eraf.close(); } catch (DirectoryException ex) { System.out.println(ex); } catch (IOException io) { System.out.println(io); } //end try updateFileTable(deviceTree.getSelectedPath()); } //end writeStuff() /** * Print the BPB of the selected device to the text area. */ private void printBPB() { if (selectedDevice == null) { JOptionPane.showMessageDialog(this, "No device selected."); return; } output.setText(printArray(selectedDevice.getBPBSector())); } //end printBPB() /** * Print the FSI of the selected device to the text area. */ private void printFSI() { if (selectedDevice == null) { JOptionPane.showMessageDialog(this, "No device selected."); return; } try { output.setText(printArray(selectedDevice.getFSI(), selectedDevice.getFSISectorNumber())); } catch(WrongFATType e) { JOptionPane.showMessageDialog(this, "FSI exists only on FAT32.\nThe selected device is not FAT32."); return; } } //end printFSI() /** * Print the FAT of the selected device to the text area. The user can specify * which FAT should be printed. It is not checked, if the user specified FAT * exists. */ private void printFAT() { if (selectedDevice == null) { JOptionPane.showMessageDialog(this, "No device selected."); return; } String result = callDialog("Please enter which FAT should be read.\n0, 1, ..."); if (result == null) { return; } else if (result.equals("")) { JOptionPane.showMessageDialog(this, "Wrong value."); return; } try { int number = (new Integer(result)).intValue(); System.out.println(number); output.setText(printArray(selectedDevice.getFATSectors(number), 512*selectedDevice.getFATSectorNumber(number))); } catch(Exception e) { JOptionPane.showMessageDialog(this, "Wrong value."); return; } } //end printFAT() /** * Print the root directory of the selected device to the text area. */ private void printRoot() { if (selectedDevice == null) { JOptionPane.showMessageDialog(this, "No device selected."); return; } output.setText(printArray(selectedDevice.getRootDir(), selectedDevice.getRootSectorNumber()*512)); } //end printRoot() /** * Print the content of the fsInfo.txt file to the text area. */ private void printFSInfo() { String content = ""; String[] lines = FileSystem.getBootFileContent(outDir+masterBootRecordFileName); for (int i=0; i < lines.length; i++) content += lines[i] + "\n"; output.setText(content); } //end printFSInfo() /** * Read one or more sectors form device and print them * on the text area. */ private void printSectors() { if (selectedDevice == null) { JOptionPane.showMessageDialog(this, "No device selected."); return; } long sectorNumber = 0; long numSectors = 1; try { String result = callDialog("Please enter the sector number"); if (result == null) return; else if (result.equals("")) { JOptionPane.showMessageDialog(this, "Wrong value."); return; } sectorNumber = (new Long(result)).longValue(); result = callDialog("Please enter the number of sectors to read."); if (result == null) return; else if (result.equals("")) { JOptionPane.showMessageDialog(this, "Wrong value."); return; } numSectors = (new Long(result)).longValue(); } catch (Exception e) { JOptionPane.showMessageDialog(this, "Wrong value."); return; } byte[] data = new byte[(int)numSectors*512]; for (long i=sectorNumber; i < sectorNumber + numSectors; i++) { byte[] buffer = new byte[512]; selectedDevice.readSector(buffer, i); System.arraycopy(buffer, 0, data, (int)(i - sectorNumber)*buffer.length, buffer.length); } output.setText(printArray(data, sectorNumber*512)); } //end printSectors() /** * Print informations about the BPB. */ private void printBPBInfo() { if (selectedDevice == null) { JOptionPane.showMessageDialog(this, "No device selected."); return; } output.setText(selectedDevice.getBPBInfo()); } //end printBPB() /** * Update the file table. All files and directories are listed which belongs * to the last node of treePath. * @param treePath the path of the tree. */ private void updateFileTable(TreePath treePath) { if (treePath == null) return; DefaultMutableTreeNode node = (DefaultMutableTreeNode)treePath.getLastPathComponent(); if (node == null) return; NodeInfo nodeInfo = (NodeInfo)node.getUserObject(); Object[] elements = treePath.getPath(); String path = ""; String deviceNameTmp; if (elements != null && elements.length > 1) { deviceNameTmp = ((DefaultMutableTreeNode)elements[1]).getUserObject().toString(); //deviceName if (FileSystem.isUnixDeviceName(deviceNameTmp)) path = deviceNameTmp; else path = deviceNameTmp + ":"; } else return; for (int i=2; i < elements.length; i++) path += System.getProperty("file.separator") + elements[i]; if (elements.length == 2) //add "\\" in case the path consist of a device name only path += System.getProperty("file.separator"); actualPath = StringOperations.removeDeviceName(path); FATDevice device = null; try { device = fileSystem.getDevice(deviceNameTmp); selectedDevice = device; } catch(Exception ex) { System.out.println(ex); return; } if (device != null) { ExtendedFile file = device.getFile(actualPath); nodeInfo.setFile(file); ExtendedFile[] files = file.listFiles(); if (files == null) return; //clear all informations from the file table fileTableModel.clear(); //insert the informations of all files of the actual directory to the file table for (int i=0; i < files.length; i++) { if (files[i].isDirectory()) { //now add the new children deviceTree.addObject(new NodeInfo(files[i].getName(), files[i])); } fileTableModel.addRow(files[i]); } fileTableModel.fireTableDataChanged(); fileTableScrollPane.repaint(); } else System.out.println("device is null"); } //end updateFileTable /** * Set ExtendedFile objects to all child nodes at the last treePath node. * @param treePath the path of the tree. */ private void setExtendedFile(TreePath treePath) { if (treePath == null) return; DefaultMutableTreeNode node = (DefaultMutableTreeNode)treePath.getLastPathComponent(); Object[] pathElements = treePath.getPath(); //add the ExtendedFile objects to the nodes java.util.Enumeration children = node.children(); while (children.hasMoreElements()) { DefaultMutableTreeNode child = (DefaultMutableTreeNode)children.nextElement(); //get the device String deviceNameTmp; FATDevice device = null; try { if (pathElements.length > 1) { deviceNameTmp = ((DefaultMutableTreeNode)pathElements[1]).getUserObject().toString(); //deviceName } else deviceNameTmp = child.getUserObject().toString(); //deviceName device = fileSystem.getDevice(deviceNameTmp); } catch(Exception ex) { System.out.println(ex); return; } //get the path String path = ""; if (FileSystem.isUnixDeviceName(deviceNameTmp)) path += deviceNameTmp; else path += deviceNameTmp + ":"; for (int i=2; i < pathElements.length; i++) path += System.getProperty("file.separator") + pathElements[i]; //set the ExtendedFile objects to the NodeInfo object stored at this node ((NodeInfo)child.getUserObject()).setFile(device.getFile(path)); } //end while } //end setExtendedFile(TreePath treePath) /** * Contains all possible chars of a hex number. */ public static char table[] = new char[]{'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; /** * Print the array as a chain of hex numbers the start line number will be zero. * @param arr the array. * @return the array as a String. */ public static String printArray(byte[] arr) { return printArray(arr, 0); } //end printArray(arr) /** * Print the given byte array as a chain of hex numbers. You can * specify a line number so that the chain is numbered. * @param arr the array. * @param lineNum a line number. * @return the array as a String. */ public static String printArray(byte[] arr, long lineNum) { String res = ""; for (int i=0; i <= arr.length/16; i++) { res += printHex(lineNum); res += "h: "; for(int j=0; j < 16; j++) { if (i*16+j >= arr.length) return res; res += printHex(arr[i*16 + j]); res += " "; } lineNum += 16; res += "\n"; } return res; } //end printArray(arr, lineNum) /** * Print the given byte as a hex number. * @param b the byte. * @return the byte as a String. */ public static String printHex(byte b) { String res = ""; res += table[((b >> 4) & 0x0F)]; res += table[(b & 0x0F)]; return res; } //end printHex(byte) /** * Print the given long as a hex number. * @param l the long. * @return the long as a String. */ public static String printHex(long l) { String res = ""; res += table[(int)((l >> 32) & 0x000000000000000F)]; res += table[(int)((l >> 28) & 0x000000000000000F)]; res += table[(int)((l >> 24) & 0x000000000000000F)]; res += table[(int)((l >> 20) & 0x000000000000000F)]; res += table[(int)((l >> 16) & 0x000000000000000F)]; res += table[(int)((l >> 12) & 0x000000000000000F)]; res += table[(int)((l >> 8) & 0x000000000000000F)]; res += table[(int)((l >> 4) & 0x000000000000000F)]; res += table[(int)(l & 0x000000000000000F)]; return res; } //end printHex(long) /**The main method * @param args the arguments */ public static void main(String[] args) { if (XXLSystem.calledFromMainMaker()) { System.out.println("RawExplorer: This class is not started from MainMaker."); return; } RawExplorer window = new RawExplorer(); window.setTitle("RawExplorer"); window.setSize(800, 600); window.setVisible(true); } //end main /** * This class represents the tree of active devices that is used by class RawExplorer. */ protected class DynamicTree extends JPanel { /** * The root node. */ protected DefaultMutableTreeNode rootNode; /** * The tree model of the tree. */ protected DefaultTreeModel treeModel; /** * The tree himself. */ protected JTree tree; /** * Create an instance of this object. */ public DynamicTree() { rootNode = new DefaultMutableTreeNode(new NodeInfo("active devices")); treeModel = new DefaultTreeModel(rootNode); tree = new JTree(treeModel); tree.setEditable(true); tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); tree.setShowsRootHandles(true); tree.addTreeSelectionListener(new TreeSelectionListener() { public void valueChanged(TreeSelectionEvent e) { updateFileTable(e.getPath()); } }); tree.addTreeExpansionListener(new TreeExpansionListener() { //in case of tree expansion, all new visible nodes must be initialized with the NodeInfo class public void treeExpanded(TreeExpansionEvent e) { TreePath treePath = e.getPath(); setExtendedFile(treePath); } //end treeExpanded //in case of tree collaps all now no longer visible nodes must be cleared of NodeInfo public void treeCollapsed(TreeExpansionEvent e) { TreePath path = e.getPath(); DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent(); java.util.Enumeration enumeration = node.children(); while(enumeration.hasMoreElements()) { NodeInfo nodeInfo = (NodeInfo)((DefaultMutableTreeNode)enumeration.nextElement()).getUserObject(); nodeInfo.removeFile(); } } //end treeCollapsed }); JScrollPane scrollPane = new JScrollPane(tree); setLayout(new GridLayout(1,0)); add(scrollPane); } /** * Remove all nodes except the root node. */ public void clear() { rootNode.removeAllChildren(); treeModel.reload(); } /** * Return the root node. * @return the root node. */ protected DefaultMutableTreeNode getRoot() { return rootNode; } /** * Remove the node given by device and path from * the tree. * @param device the device. * @param path the path from the tree */ public void removeNode(FATDevice device, String path) { Enumeration enumeration = rootNode.children(); DefaultMutableTreeNode deviceNode = null; boolean found = false; while (enumeration.hasMoreElements()) { deviceNode = (DefaultMutableTreeNode)enumeration.nextElement(); if (((NodeInfo)deviceNode.getUserObject()).message.equals(device.getRealDeviceName())) { found = true; break; } } if (found) { removeNode(deviceNode, StringOperations.removeDeviceName(path)); } } //end removeNode(FATDevice device, String path) /** * Remove the node given by path from the given node or * of a child of it. * @param node the node where the search starts. * @param path the way through the tree. The last path * component represents the node that should be removed. * @return true if the node could be removed; false otherwise. */ private boolean removeNode(DefaultMutableTreeNode node, String path) { StringTokenizer st = new StringTokenizer(path, System.getProperty("file.separator")); String name; if (st.hasMoreTokens()) name = st.nextToken(); else return false; Enumeration enumeration = node.children(); while (enumeration.hasMoreElements()) { DefaultMutableTreeNode tmpNode = (DefaultMutableTreeNode)enumeration.nextElement(); if (((NodeInfo)tmpNode.getUserObject()).message.equals(name)) //we found the searched node { if (!st.hasMoreTokens()) //we reached the one and only node { treeModel.removeNodeFromParent(tmpNode); return true; } else if (removeNode(tmpNode, path.substring(name.length()))) return true; } } return false; } /** * Remove the currently selected node. */ public void removeCurrentNode() { TreePath currentSelection = tree.getSelectionPath(); if (currentSelection != null) { DefaultMutableTreeNode currentNode = (DefaultMutableTreeNode)(currentSelection.getLastPathComponent()); MutableTreeNode parent = (MutableTreeNode)(currentNode.getParent()); if (parent != null) { treeModel.removeNodeFromParent(currentNode); return; } } } /** * Add child to the currently selected node. * @param child the child. * @return the DefaultMutableTreeNode */ public DefaultMutableTreeNode addObject(Object child) { DefaultMutableTreeNode parentNode = null; TreePath parentPath = tree.getSelectionPath(); if (parentPath == null) { parentNode = rootNode; } else { parentNode = (DefaultMutableTreeNode)(parentPath.getLastPathComponent()); } return addObject(parentNode, child, true); } /** * Add the child to the parent node. * @param parent the parent node. * @param child the child. * @return the DefaultMutableTreeNode */ public DefaultMutableTreeNode addObject(DefaultMutableTreeNode parent, Object child) { return addObject(parent, child, false); } /** * Add the child to the parent and make it visible depending on shouldBeVisible. * @param parent the parent node. * @param child the child. * @param shouldBeVisible if true then it visible. * @return the DefaultMutableTreeNode */ public DefaultMutableTreeNode addObject(DefaultMutableTreeNode parent, Object child, boolean shouldBeVisible) { for (int i=0; i < parent.getChildCount(); i++) { if (((NodeInfo)((DefaultMutableTreeNode)parent.getChildAt(i)).getUserObject()).toString().equals(((NodeInfo)child).toString())) return null; } DefaultMutableTreeNode childNode = new DefaultMutableTreeNode(child); if (parent == null) { parent = rootNode; } treeModel.insertNodeInto(childNode, parent, parent.getChildCount()); // Make sure the user can see the lovely new node. if (shouldBeVisible) { tree.scrollPathToVisible(new TreePath(childNode.getPath())); //initialize the ExtendedFile objects setExtendedFile(new TreePath(parent.getPath())); } return childNode; } /** * The listener of the tree. */ class MyTreeModelListener implements TreeModelListener { /** * Is called if the tree nodes changed. * @param e the tree node. */ public void treeNodesChanged(TreeModelEvent e) { DefaultMutableTreeNode node; node = (DefaultMutableTreeNode)(e.getTreePath().getLastPathComponent()); /* * If the event lists children, then the changed * node is the child of the node we've already * gotten. Otherwise, the changed node and the * specified node are the same. */ try { int index = e.getChildIndices()[0]; node = (DefaultMutableTreeNode)(node.getChildAt(index)); } catch (NullPointerException exc) { } } /** * Is calles if tree nodes are inserted. * @param e the tree node. */ public void treeNodesInserted(TreeModelEvent e) { } /** * Is calles if tree nodes are removed. * @param e the tree node. */ public void treeNodesRemoved(TreeModelEvent e) { } /** * Is called if the structure of the tree has changed. * @param e the tree node. */ public void treeStructureChanged(TreeModelEvent e) { } } //end inner class /** * Return the selected path. * @return the selected path. */ public TreePath getSelectedPath() { return tree.getSelectionPath(); } /** * Scroll the path to visible. * @param node the node, which path should be scroll to visible. */ public void scrollPathToVisible(DefaultMutableTreeNode node) { tree.scrollPathToVisible(new TreePath(node.getPath())); } /** * Removes all children from the selected path. */ public void removeAllChildren() { TreePath treePath = tree.getSelectionPath(); DefaultMutableTreeNode selectedNode = (DefaultMutableTreeNode)treePath.getLastPathComponent(); java.util.Enumeration enumeration = selectedNode.children(); while (enumeration.hasMoreElements()) { DefaultMutableTreeNode n = (DefaultMutableTreeNode)enumeration.nextElement(); treeModel.removeNodeFromParent(n); } } } //end class DynamicTree } //end class RawExplorer /** * This class is the table model of the file table. It is used to manage the content of * the file table. */ class FileTableModel extends AbstractTableModel { /** * Instance of RawExplorer */ private RawExplorer RawExplorer; /** * The names of the columns. */ protected final String[] columnNames = {"Name", "Size", "Type", "Last Modificated", "Created"}; /** * Contains the informations of the rows of the file table. * Each row is represented by a RowNode which contains the * different informations of a file. */ protected Vector rowData = new Vector(); /** * Contains the informations to show in the file table for a file. */ class RowNode { /** * The name of the file or directory. */ String name; /** * The size in bytes of the file or directory. */ long size; /** * The type is either "DIR", "FILE", "ROOT_DIR", or "UNKNOWN". */ String type; /** * The date of the last modification. */ DirectoryDate lastModificationDate; /** * The time of the last modification. */ DirectoryTime lastModificationTime; /** * The creation date. */ DirectoryDate creationDate; /** * The creation time. */ DirectoryTime creationTime; /** * Set a new name. * @param name the new name. */ void setName(String name) { this.name = name; } /** * Set a new size. * @param size the new size. */ void setSize(long size) { this.size = size; } /** * Set the type. * @param attribute indicates the type. */ void setType(byte attribute) { if (((attribute & DIR.ATTR_LONG_NAME_MASK) != DIR.ATTR_LONG_NAME) && (attribute & (DIR.ATTR_DIRECTORY | DIR.ATTR_VOLUME_ID)) == DIR.ATTR_VOLUME_ID) type = "<ROOT-DIR>"; else if (((attribute & DIR.ATTR_LONG_NAME_MASK) != DIR.ATTR_LONG_NAME) && (attribute & (DIR.ATTR_DIRECTORY | DIR.ATTR_VOLUME_ID)) == DIR.ATTR_DIRECTORY) type = "<DIR>"; else if (((attribute & DIR.ATTR_LONG_NAME_MASK) != DIR.ATTR_LONG_NAME) && (attribute & (DIR.ATTR_DIRECTORY | DIR.ATTR_VOLUME_ID)) == 0x00) type = "FILE"; else type = "UNKNOWN"; } /** * Set the last modification date and time. * @param modDate the new last modification date. * @param modTime the new last modification time. */ void setModification(DirectoryDate modDate, DirectoryTime modTime) { lastModificationDate = modDate; lastModificationTime = modTime; } /** * Set the new creation time. * @param creDate the new creation date. * @param creTime the new creation time. */ void setCreation(DirectoryDate creDate, DirectoryTime creTime) { creationDate = creDate; creationTime = creTime; } } /** * Create an instance of this object. * @param fst the RawExplorer. */ public FileTableModel(RawExplorer fst) { this.RawExplorer = fst; } /** * Return the number of columns. * @return the number of columns. */ public int getColumnCount() { return columnNames.length; } /** * Return the number of rows. * @return the number of rows. */ public int getRowCount() { return rowData.size(); } /** * Return the column name of column col. * @param col the column number. * @return the column name of colum col. */ public String getColumnName(int col) { return columnNames[col]; } /** * Return the content of the file table at (row, col). * @param row the row. * @param col the column. * @return the content of the file table at (row, col). */ public Object getValueAt(int row, int col) { RowNode node = (RowNode)rowData.get(row); Object obj; switch (col) { case 0 : {obj = node.name; break;} case 1 : {obj = new Long(node.size); break;} case 2 : {obj = node.type; break;} case 3 : {obj = node.lastModificationDate.toString() + ", " + node.lastModificationTime.toString(); break;} case 4 : {obj = node.creationDate.toString() + ", " + node.creationTime.toString(); break;} default : {obj = "null";} } return obj; } /** * Return the class at column c. * @param c the column number. * @return the class. */ public Class getColumnClass(int c) { return getValueAt(0, c).getClass(); } /** * Return if the file table cell at (row, col) is editable. * @param row the row. * @param col the column. * @return true if the file table cell[row][col] is editable; otherwise false. */ public boolean isCellEditable(int row, int col) { //Note that the data/cell address is constant, //no matter where the cell appears onscreen. if (col < 2) return false; else return true; } /** * Remove all contnet of the file table except the column names. */ public void clear() { for (int i=0; i < columnNames.length; i++) rowData.clear(); } /** * Add a new row at the end of the file table. * @param file contains the informations that should stored at the new row. */ public void addRow(ExtendedFile file) { int row = getRowCount(); for (int i=0; i < columnNames.length; i++) setValueAt(file, row, i); } /** * Set the content of cell (row, col) to the given value. * @param value the new content. The value must be a ExtendedFile object. * @param row the row. * @param col the column. */ public void setValueAt(Object value, int row, int col) { ExtendedFile file = null; try { file = (ExtendedFile)value; } catch (ClassCastException e) { JOptionPane.showMessageDialog(RawExplorer, e); return; } RowNode node; if (rowData.size() <= row) node = new RowNode(); else node = (RowNode)rowData.get(row); if (col == 0) node.setName(file.getName()); else if (col == 1) node.setSize(file.length()); else if (col == 2) node.setType(file.getAttribute()); else if (col == 3) node.setModification(file.getLastModifiedDate(), file.getLastModifiedTime()); else if (col == 4) node.setCreation(file.getCreationDate(), file.getCreationTime()); if (rowData.size() <= row) rowData.add(node); } /** * Return true if the file stored at row number 'row' * is of type directory; false otherwise. * @param row the row number. * @return true if the file stored at row number 'row' * is of type directory; false otherwise. */ public boolean isDirectory(int row) { if (row > rowData.size() || row < 0) return false; return ((String)getValueAt(row, 2)).equals("<DIR>"); } } //end class FileTableModel