/*- * Copyright (C) 2008 Erik Larsson * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.catacombae.hfsexplorer.gui; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.util.LinkedList; import java.util.List; import javax.swing.JDialog; import javax.swing.JFileChooser; import javax.swing.JOptionPane; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import org.catacombae.hfsexplorer.GUIUtil; import org.catacombae.hfsexplorer.IOUtil; import org.catacombae.util.Util; import org.catacombae.hfsexplorer.fs.ResourceForkReader; import org.catacombae.hfsexplorer.types.resff.ReferenceListEntry; import org.catacombae.hfsexplorer.types.resff.ResourceMap; import org.catacombae.hfsexplorer.types.resff.ResourceName; import org.catacombae.hfsexplorer.types.resff.ResourceType; import org.catacombae.io.ReadableRandomAccessStream; import org.catacombae.util.Util.Pair; /** * @author <a href="http://www.catacombae.org/" target="_top">Erik Larsson</a> */ public class ResourceForkViewPanel extends javax.swing.JPanel { private ResourceForkReader reader = null; /** * An item as it is displayed in the list view over available resources. * Its toString method decides how it is displayed to the user. */ private class ListItem { ResourceType type; ReferenceListEntry entry; ResourceName name; long size; public ListItem(ResourceType type, ReferenceListEntry entry, ResourceName name, long size) { this.type = type; this.entry = entry; this.name = name; this.size = size; } @Override public String toString() { try { StringBuilder sb = new StringBuilder(); sb.append(new String(type.getType(), "MacRoman")); if(name != null) sb.append(" \"").append(new String(name.getName(), "MacRoman")).append("\""); return sb.toString(); } catch(Exception e) { e.printStackTrace(); return "{" + e.getClass().getSimpleName() + " in resource id " + entry.getResourceID() + "}"; } } } /** Creates new form ResourceForkViewPanel */ public ResourceForkViewPanel(ResourceForkReader startupReader) { initComponents(); resourceList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); loadResourceFork(startupReader); resourceList.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { Object o = resourceList.getSelectedValue(); if(o instanceof ListItem) setSelectedItem((ListItem)o); else if(o != null) JOptionPane.showMessageDialog(resourceList, "Unexpected type in list: " + o.getClass()); } }); viewButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Object selection = resourceList.getSelectedValue(); if(selection != null && selection instanceof ListItem) { ListItem selectedItem = (ListItem) selection; JDialog d = new JDialog(JOptionPane.getFrameForComponent(ResourceForkViewPanel.this), selection.toString(), true); DisplayTextFilePanel dtfp = new DisplayTextFilePanel(); dtfp.loadStream(reader.getResourceStream(selectedItem.entry)); d.add(dtfp); d.pack(); d.setLocationRelativeTo(null); d.setVisible(true); } } }); extractButton.addActionListener(new ActionListener() { private JFileChooser fileChooser = new JFileChooser(); { fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); fileChooser.setMultiSelectionEnabled(false); } public void actionPerformed(ActionEvent e) { Object selection = resourceList.getSelectedValue(); if(selection != null && selection instanceof ListItem) { ListItem selectedItem = (ListItem) selection; if(fileChooser.showSaveDialog(ResourceForkViewPanel.this) == JFileChooser.APPROVE_OPTION) { File saveFile = fileChooser.getSelectedFile(); if(saveFile.exists()) { int res = JOptionPane.showConfirmDialog(ResourceForkViewPanel.this, "The file already exists. Do you want to overwrite?", "Confirm overwrite", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE); if(res != JOptionPane.YES_OPTION) return; } ReadableRandomAccessStream in = null; FileOutputStream fos = null; try { in = reader.getResourceStream(selectedItem.entry); fos = new FileOutputStream(saveFile); IOUtil.streamCopy(in, fos, 65536); } catch(FileNotFoundException fnfe) { JOptionPane.showMessageDialog(ResourceForkViewPanel.this, "Could not open file \"" + saveFile.getPath() + "\" for writing...", "Error", JOptionPane.ERROR_MESSAGE); } catch(IOException ioe) { ioe.printStackTrace(); GUIUtil.displayExceptionDialog(ioe, ResourceForkViewPanel.this); } finally { if(in != null) in.close(); if(fos != null) { try { fos.close(); } catch(IOException ex) { ex.printStackTrace(); GUIUtil.displayExceptionDialog(ex, ResourceForkViewPanel.this); } } } } } } }); } public final void loadResourceFork(ResourceForkReader reader) { if(reader != null) { ListItem[] allItems = listAllItems(reader); resourceList.setEnabled(true); resourceList.setListData(allItems); resourceListLabel.setText("Resource list (" + allItems.length + " items):"); } else { resourceList.setEnabled(false); resourceList.setListData(new Object[0]); resourceListLabel.setText("Resource list:"); } setSelectedItem(null); this.reader = reader; } private ListItem[] listAllItems(ResourceForkReader reader) { //System.err.println("listAllItems(): getting resource map"); ResourceMap resMap = reader.getResourceMap(); LinkedList<ListItem> result = new LinkedList<ListItem>(); //System.err.println("listAllItems(): getting reference list for " + resMap); List<Pair<ResourceType, ReferenceListEntry[]>> refList = resMap.getReferenceList(); for(Pair<ResourceType, ReferenceListEntry[]> p : refList) { ResourceType type = p.getA(); for(ReferenceListEntry entry : p.getB()) { //System.err.println("listAllItems(): getting name by reflist entry " + entry); ResourceName name = resMap.getNameByReferenceListEntry(entry); long size = reader.getDataLength(entry); result.add(new ListItem(type, entry, name, size)); } } return result.toArray(new ListItem[result.size()]); } private void setSelectedItem(ListItem li) { final boolean enabled; if(li == null) enabled = false; else enabled = true; extractButton.setEnabled(enabled); viewButton.setEnabled(enabled); nameField.setEnabled(enabled); typeField.setEnabled(enabled); idField.setEnabled(enabled); sizeField.setEnabled(enabled); attributesField.setEnabled(enabled); if(!enabled) { nameField.setText(""); typeField.setText(""); idField.setText(""); sizeField.setText(""); attributesField.setText(""); } else { String nameString; if(li.name != null) { try { nameString = new String(li.name.getName(), "MacRoman"); } catch(Exception e) { e.printStackTrace(); nameString = "[Could not decode: " + e.toString() + "]"; } } else { nameString = null; } String typeString; try { typeString = new String(li.type.getType(), "MacRoman"); } catch(Exception e) { e.printStackTrace(); typeString = "[Could not decode: " + e.toString() + "]"; } if(nameField == null) { nameField.setEnabled(false); nameField.setName(""); } else nameField.setText(nameString); typeField.setText(typeString); idField.setText("" + li.entry.getResourceID()); sizeField.setText(li.size + " bytes"); attributesField.setText("0x" + Util.toHexStringBE(li.entry.getResourceAttributes())); } } /** This method is called from within the constructor to * initialize the form. * WARNING: Do NOT modify this code. The content of this method is * always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents private void initComponents() { resourceListLabel = new javax.swing.JLabel(); resourceListScroller = new javax.swing.JScrollPane(); resourceList = new javax.swing.JList(); fieldsPanel = new javax.swing.JPanel(); nameLabel = new javax.swing.JLabel(); nameField = new javax.swing.JTextField(); typeLabel = new javax.swing.JLabel(); typeField = new javax.swing.JTextField(); idLabel = new javax.swing.JLabel(); idField = new javax.swing.JTextField(); sizeLabel = new javax.swing.JLabel(); sizeField = new javax.swing.JTextField(); attributesLabel = new javax.swing.JLabel(); attributesField = new javax.swing.JTextField(); extractButton = new javax.swing.JButton(); viewButton = new javax.swing.JButton(); resourceListLabel.setText("[This label is set programmatically]"); resourceList.setModel(new javax.swing.AbstractListModel() { String[] strings = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" }; public int getSize() { return strings.length; } public Object getElementAt(int i) { return strings[i]; } }); resourceListScroller.setViewportView(resourceList); nameLabel.setText("Name:"); nameField.setEditable(false); nameField.setText("jTextField1"); nameField.setOpaque(false); typeLabel.setText("Type:"); typeField.setEditable(false); typeField.setText("jTextField2"); typeField.setOpaque(false); idLabel.setText("ID:"); idField.setEditable(false); idField.setText("jTextField3"); idField.setOpaque(false); sizeLabel.setText("Size:"); sizeField.setEditable(false); sizeField.setText("jTextField4"); sizeField.setOpaque(false); attributesLabel.setText("Attributes:"); attributesField.setEditable(false); attributesField.setText("jTextField5"); attributesField.setOpaque(false); org.jdesktop.layout.GroupLayout fieldsPanelLayout = new org.jdesktop.layout.GroupLayout(fieldsPanel); fieldsPanel.setLayout(fieldsPanelLayout); fieldsPanelLayout.setHorizontalGroup( fieldsPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(fieldsPanelLayout.createSequentialGroup() .add(fieldsPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(nameLabel) .add(typeLabel) .add(idLabel) .add(sizeLabel) .add(attributesLabel)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(fieldsPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(attributesField, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 227, Short.MAX_VALUE) .add(sizeField, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 227, Short.MAX_VALUE) .add(idField, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 227, Short.MAX_VALUE) .add(nameField, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 227, Short.MAX_VALUE) .add(typeField, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 227, Short.MAX_VALUE))) ); fieldsPanelLayout.setVerticalGroup( fieldsPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(fieldsPanelLayout.createSequentialGroup() .add(fieldsPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(nameLabel) .add(nameField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(fieldsPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(typeLabel) .add(typeField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(fieldsPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(idLabel) .add(idField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(fieldsPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(sizeLabel) .add(sizeField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(fieldsPanelLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(attributesLabel) .add(attributesField, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE))) ); extractButton.setText("Save to file..."); viewButton.setText("View as text"); org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this); this.setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(org.jdesktop.layout.GroupLayout.TRAILING, layout.createSequentialGroup() .addContainerGap() .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.TRAILING) .add(org.jdesktop.layout.GroupLayout.LEADING, resourceListScroller, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 283, Short.MAX_VALUE) .add(org.jdesktop.layout.GroupLayout.LEADING, resourceListLabel) .add(layout.createSequentialGroup() .add(viewButton) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(extractButton)) .add(org.jdesktop.layout.GroupLayout.LEADING, fieldsPanel, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) .add(layout.createSequentialGroup() .addContainerGap() .add(resourceListLabel) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(resourceListScroller, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 99, Short.MAX_VALUE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(fieldsPanel, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE) .addPreferredGap(org.jdesktop.layout.LayoutStyle.RELATED) .add(layout.createParallelGroup(org.jdesktop.layout.GroupLayout.BASELINE) .add(extractButton) .add(viewButton)) .addContainerGap()) ); }// </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JTextField attributesField; private javax.swing.JLabel attributesLabel; private javax.swing.JButton extractButton; private javax.swing.JPanel fieldsPanel; private javax.swing.JTextField idField; private javax.swing.JLabel idLabel; private javax.swing.JTextField nameField; private javax.swing.JLabel nameLabel; private javax.swing.JList resourceList; private javax.swing.JLabel resourceListLabel; private javax.swing.JScrollPane resourceListScroller; private javax.swing.JTextField sizeField; private javax.swing.JLabel sizeLabel; private javax.swing.JTextField typeField; private javax.swing.JLabel typeLabel; private javax.swing.JButton viewButton; // End of variables declaration//GEN-END:variables }