Graphical disk image importer
[jpcrr.git] / org / jpc / pluginsaux / ImportDiskImage.java
blobd121457668e4da6b64661d4e34c7833dd82e76cd
1 /*
2 JPC-RR: A x86 PC Hardware Emulator
3 Release 1
5 Copyright (C) 2007-2009 Isis Innovation Limited
6 Copyright (C) 2009 H. Ilari Liusvaara
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License version 2 as published by
10 the Free Software Foundation.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 Based on JPC x86 PC Hardware emulator,
22 A project from the Physics Dept, The University of Oxford
24 Details about original JPC can be found at:
26 www-jpc.physics.ox.ac.uk
30 package org.jpc.pluginsaux;
32 import org.jpc.pluginsaux.ConstantTableLayout;
33 import static org.jpc.Misc.errorDialog;
34 import org.jpc.diskimages.TreeDirectoryFile;
35 import org.jpc.diskimages.ImageMaker;
36 import org.jpc.diskimages.ImageLibrary;
37 import org.jpc.diskimages.DiskImage;
38 import org.jpc.diskimages.RawDiskImage;
39 import org.jpc.diskimages.TreeRawDiskImage;
40 import org.jpc.diskimages.FileRawDiskImage;
41 import static org.jpc.Misc.tempname;
42 import static org.jpc.Misc.callShowOptionDialog;
44 import javax.swing.*;
45 import java.util.*;
46 import java.awt.event.*;
47 import java.awt.*;
48 import java.io.*;
50 public class ImportDiskImage implements ActionListener, KeyListener
52 private JFrame window;
53 private JPanel panel;
54 private JLabel imageNameLabel;
55 private JTextField imageName;
56 private JLabel imageFileLabel;
57 private JLabel imageTypeLabel;
58 private JTextField imageFile;
59 private JComboBox imageType;
60 private JLabel feedback;
61 private JButton importDisk;
62 private JButton cancel;
63 private JCheckBox stdGeometry;
64 private JCheckBox doublesided;
65 private JLabel sidesLabel;
66 private JTextField sides;
67 private JLabel sidesFixed;
68 private JLabel sectorsLabel;
69 private JTextField sectors;
70 private JLabel sectorsFixed;
71 private JLabel tracksLabel;
72 private JTextField tracks;
73 private JLabel tracksFixed;
74 private JCheckBox volumeLabelLabel;
75 private JTextField volumeLabel;
76 private JCheckBox createTimeLabel;
77 private JTextField createTime;
78 private static String NOT_VALID = "<No valid choice>";
79 private static String FLOPPY = "Floppy Disk";
80 private static String HDD = "Hard Disk";
81 private static String CDROM = "CD-ROM Disk";
82 private static String BIOS = "BIOS image";
84 private boolean fileSelected;
85 private long fileSelectedLength;
86 private boolean directorySelected;
87 private boolean constructed;
88 private long fileCase;
90 public ImportDiskImage()
92 int height = 9;
93 fileCase = -1; //Initial.
94 window = new JFrame("Import Disk Image");
95 ConstantTableLayout layout = new ConstantTableLayout();
96 panel = new JPanel(layout);
97 window.add(panel);
99 add(imageNameLabel = new JLabel("New image name"), 0, 0, 1, 1);
100 add(imageName = new JTextField("", 50), 1, 0, 1, 1);
101 imageName.addKeyListener(this);
103 add(imageFileLabel = new JLabel("Image file/directory"), 0, 1, 1, 1);
104 add(imageFile = new JTextField("", 50), 1, 1, 1, 1);
105 imageFile.addKeyListener(this);
107 add(imageTypeLabel = new JLabel("Image Type"), 0, 2, 1, 1);
108 add(imageType = new JComboBox(), 1, 2, 1, 1);
109 imageType.addActionListener(this);
110 setNoValidChoice(imageType);
112 add(stdGeometry = new JCheckBox("Standard geometry"), 0, 3, 1, 1);
113 stdGeometry.setEnabled(false);
114 stdGeometry.addActionListener(this);
116 add(doublesided = new JCheckBox("Double-sided"), 1, 3, 1, 1);
117 doublesided.setEnabled(false);
118 doublesided.addActionListener(this);
120 add(sidesLabel = new JLabel("Sides"), 0, 4, 1, 1);
121 add(sides = new JTextField("16", 50), 1, 4, 1, 1);
122 add(sidesFixed = new JLabel("N/A"), 1, 4, 1, 1);
123 sides.setVisible(false);
124 sides.addKeyListener(this);
126 add(sectorsLabel = new JLabel("Sectors"), 0, 5, 1, 1);
127 add(sectors = new JTextField("63", 50), 1, 5, 1, 1);
128 add(sectorsFixed = new JLabel("N/A"), 1, 5, 1, 1);
129 sectors.setVisible(false);
130 sectors.addKeyListener(this);
132 add(tracksLabel = new JLabel("Tracks"), 0, 6, 1, 1);
133 add(tracks = new JTextField("16", 50), 1, 6, 1, 1);
134 add(tracksFixed = new JLabel("N/A"), 1, 6, 1, 1);
135 tracks.setVisible(false);
136 tracks.addKeyListener(this);
138 add(volumeLabelLabel = new JCheckBox("Volume label"), 0, 7, 1, 1);
139 add(volumeLabel = new JTextField("", 50), 1, 7, 1, 1);
140 volumeLabel.setEnabled(false);
141 volumeLabelLabel.setEnabled(false);
142 volumeLabelLabel.addActionListener(this);
143 volumeLabel.addKeyListener(this);
145 add(createTimeLabel = new JCheckBox("File timestamps"), 0, 8, 1, 1);
146 add(createTime = new JTextField("19900101000000", 50), 1, 8, 1, 1);
147 createTime.setEnabled(false);
148 createTimeLabel.setEnabled(false);
149 createTimeLabel.addActionListener(this);
150 createTime.addKeyListener(this);
152 add(importDisk = new JButton("Import"), 0, height, 1, 1);
153 add(cancel = new JButton("Cancel"), 1, height, 1, 1);
154 importDisk.setActionCommand("IMPORT");
155 importDisk.addActionListener(this);
156 importDisk.setEnabled(false);
157 cancel.setActionCommand("CANCEL");
158 cancel.addActionListener(this);
160 add(feedback = new JLabel(""), 0, height + 1, 2, 1);
161 revalidateForm();
163 constructed = true;
164 keyTyped(null);
166 window.pack();
167 window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
168 window.setVisible(true);
171 private void setNoValidChoice(JComboBox box)
173 box.removeAllItems();
174 box.addItem(NOT_VALID);
175 box.setSelectedItem(NOT_VALID);
176 box.setEnabled(false);
179 private void add(JComponent component, int x, int y, int w, int h)
181 ConstantTableLayout.Placement c = new ConstantTableLayout.Placement(x, y, w, h);
182 panel.add(component, c);
185 private int checkVolumeLabel(String text)
187 if(text.length() > 11)
188 return 1;
189 for(int i = 0; i < text.length(); i++) {
190 char c = text.charAt(i);
191 if(c == 34 || c == 124)
192 return 2;
193 if(c >= 33 && c <= 41)
194 continue;
195 if(c == 45)
196 continue;
197 if(c >= 48 && c <= 57)
198 continue;
199 if(c >= 64 && c <= 90)
200 continue;
201 if(c >= 94 && c <= 126)
202 continue;
203 if(c >= 160 && c <= 255)
204 continue;
205 return 2;
207 return 0;
210 private boolean checkTimeStamp(String text)
212 try {
213 TreeDirectoryFile.dosFormatTimeStamp(text);
214 return true;
215 } catch(Exception e) {
216 return false;
220 private void revalidateForm()
222 if("".equals(imageName.getText())) {
223 feedback.setText("No image name specified");
224 importDisk.setEnabled(false);
225 return;
227 if(imageName.getText().startsWith("/")) {
228 feedback.setText("Image name can't start with '/'");
229 importDisk.setEnabled(false);
230 return;
232 if(imageName.getText().indexOf("//") >= 0) {
233 feedback.setText("Image name can't have '//'");
234 importDisk.setEnabled(false);
235 return;
237 if(imageName.getText().lastIndexOf("/") == imageName.getText().length() - 1) {
238 feedback.setText("Image name can't end in '/'");
239 importDisk.setEnabled(false);
240 return;
242 if("".equals(imageFile.getText())) {
243 feedback.setText("No image file specified");
244 importDisk.setEnabled(false);
245 return;
247 String _filename = imageFile.getText();
248 File fileObject = new File(_filename);
249 if(!fileObject.exists()) {
250 feedback.setText("Image file does not exist");
251 importDisk.setEnabled(false);
252 return;
254 if(!fileObject.isFile() && !fileObject.isDirectory()) {
255 feedback.setText("Special devices not allowed as image files");
256 importDisk.setEnabled(false);
257 return;
260 int sides = getSides();
261 int sectors = getSectors();
262 int tracks = getTracks();
263 String type = (String)imageType.getSelectedItem();
264 if(FLOPPY.equals(type)) {
265 if(sides < 1 || sides > 2) {
266 feedback.setText("Sides out of range (1-2)");
267 importDisk.setEnabled(false);
268 return;
270 if(sectors < 1 || sectors > 255) {
271 feedback.setText("Sectors out of range (1-255)");
272 importDisk.setEnabled(false);
273 return;
275 if(tracks < 1 || tracks > 256) {
276 feedback.setText("Tracks out of range (1-256)");
277 importDisk.setEnabled(false);
278 return;
280 } else if(HDD.equals(type)) {
281 if(sides < 1 || sides > 16) {
282 feedback.setText("Sides out of range (1-16)");
283 importDisk.setEnabled(false);
284 return;
286 if(sectors < 1 || sectors > 63) {
287 feedback.setText("Sectors out of range (1-63)");
288 importDisk.setEnabled(false);
289 return;
291 if(tracks < 1 || tracks > 1024) {
292 feedback.setText("Tracks out of range (1-1024)");
293 importDisk.setEnabled(false);
294 return;
296 } else if(CDROM.equals(type)) {
297 } else if(BIOS.equals(type)) {
298 } else {
299 feedback.setText("Bad image type");
300 importDisk.setEnabled(false);
301 return;
303 if(volumeLabelLabel.isEnabled() && volumeLabelLabel.isSelected()) {
304 int res = 0;
305 res = checkVolumeLabel(volumeLabel.getText());
306 if(res == 1) {
307 feedback.setText("Volume label too long");
308 importDisk.setEnabled(false);
309 return;
311 if(res == 2) {
312 feedback.setText("Invalid character in volume label");
313 importDisk.setEnabled(false);
314 return;
317 if(createTimeLabel.isEnabled() && createTimeLabel.isSelected()) {
318 if(!checkTimeStamp(createTime.getText())) {
319 feedback.setText("Bad timestamp (YYYYMMDDHHMMSS)");
320 importDisk.setEnabled(false);
321 return;
324 feedback.setText("");
325 importDisk.setEnabled(true);
328 public class ImportTask implements Runnable
330 String name;
331 String file;
332 int typeCode;
333 int sides;
334 int sectors;
335 int tracks;
336 String label;
337 String timestamp;
339 private byte[] writeImage(RandomAccessFile out, String src, ImageMaker.IFormat format) throws IOException
341 RawDiskImage input;
342 File srcFile = new File(src);
343 if(format.typeCode == 3) {
344 //Read the image.
345 if(!srcFile.isFile())
346 throw new IOException("BIOS images can only be made out of regular files");
347 RandomAccessFile input2 = new RandomAccessFile(src, "r");
348 return ImageMaker.makeBIOSImage(out, input2, format);
349 } else if(format.typeCode == 2) {
350 if(!srcFile.isFile())
351 throw new IOException("CD images can only be made out of regular files");
352 FileRawDiskImage input2 = new FileRawDiskImage(src);
353 return ImageMaker.makeCDROMImage(out, input2, format);
354 } else if(format.typeCode == 0 || format.typeCode == 1) {
355 if(srcFile.isFile()) {
356 input = new FileRawDiskImage(src);
357 } else if(srcFile.isDirectory()) {
358 TreeDirectoryFile root = TreeDirectoryFile.importTree(src, format.volumeLabel, format.timestamp);
359 input = new TreeRawDiskImage(root, format, format.volumeLabel);
360 } else
361 throw new IOException("Source is neither regular file nor directory");
362 return ImageMaker.makeFloppyHDDImage(out, input, format);
363 } else
364 throw new IOException("BUG: Invalid image type code " + format.typeCode);
367 private byte[] warpedRun() throws Exception
369 byte[] id = null;
370 RandomAccessFile output;
371 String finalName = DiskImage.getLibrary().getPathPrefix() + name;
372 ImageMaker.IFormat fmt = new ImageMaker.IFormat(null);
373 fmt.typeCode = typeCode;
374 fmt.tracks = tracks;
375 fmt.sectors = sectors;
376 fmt.sides = sides;
377 fmt.timestamp = timestamp;
378 fmt.volumeLabel = label;
380 File dirFile = new File(finalName.substring(0, finalName.lastIndexOf("/")));
381 if(!dirFile.isDirectory())
382 if(!dirFile.mkdirs())
383 throw new IOException("Can't create directory '" + dirFile.getAbsolutePath() + "'");
385 String temporaryName = tempname(finalName);
386 File firstArgFile = new File(temporaryName);
387 while(firstArgFile.exists())
388 firstArgFile = new File(temporaryName = tempname(finalName));
389 firstArgFile.deleteOnExit();
391 output = new RandomAccessFile(firstArgFile, "rw");
392 try {
393 id = writeImage(output, file, fmt);
394 } catch(Exception e) {
395 output.close();
396 firstArgFile.delete();
397 throw e;
399 firstArgFile.renameTo(new File(finalName));
400 DiskImage.getLibrary().insertFileName(new ImageLibrary.ByteArray(id), finalName, name);
401 return id;
404 public void run()
406 byte[] id = null;
407 try {
408 id = warpedRun();
409 } catch(Exception e) {
410 doImportFinished(e, null);
411 return;
413 doImportFinished(null, id);
417 private void importDisk() throws IOException
419 String _imageName = imageName.getText();
420 String _imageFile = imageFile.getText();
421 String _imageType = (String)imageType.getSelectedItem();
422 int sides = getSides();
423 int sectors = getSectors();
424 int tracks = getTracks();
425 String label = null;
426 if(volumeLabelLabel.isEnabled() && volumeLabelLabel.isSelected())
427 label = volumeLabel.getText();
428 String timestamp = null;
429 if(createTimeLabel.isEnabled() && createTimeLabel.isSelected())
430 timestamp = createTime.getText();
431 int typeCode = -1;
432 if(FLOPPY.equals(_imageType)) {
433 typeCode = 0;
434 if(sides < 1 || sides > 2 || sectors < 1 || sectors > 255 || tracks < 1 || tracks > 256)
435 throw new IOException("Illegal floppy geometry " + sides + " sides " + sectors + " sectors " +
436 tracks + " tracks");
437 } else if(HDD.equals(_imageType)) {
438 typeCode = 1;
439 if(sides < 1 || sides > 16 || sectors < 1 || sectors > 63 || tracks < 1 || tracks > 1024)
440 throw new IOException("Illegal HDD geometry " + sides + " sides " + sectors + " sectors " +
441 tracks + " tracks");
442 } else if(CDROM.equals(_imageType)) {
443 typeCode = 2;
444 } else if(BIOS.equals(_imageType)) {
445 typeCode = 3;
446 } else {
447 throw new IOException("Illegal Image type: " + _imageType);
449 ImportTask t = new ImportTask();
450 t.name = _imageName;
451 t.file = _imageFile;
452 t.typeCode = typeCode;
453 t.sides = sides;
454 t.sectors = sectors;
455 t.tracks = tracks;
456 t.label = label;
457 t.timestamp = timestamp;
458 (new Thread(t)).start();
461 private void doImportFinished(Exception failure, byte[] id)
463 final Exception failure2 = failure;
464 final byte[] id2 = id;
465 try {
466 SwingUtilities.invokeLater(new Runnable() { public void run() { importFinished(failure2, id2); }});
467 } catch(Exception e) {
471 private void importFinished(Exception failure, byte[] id)
473 if(failure != null) {
474 errorDialog(failure, "Error making image", window, "Dismiss");
475 cancel.setEnabled(true);
476 keyTyped(null);
477 } else {
478 //Get rid of window.
479 callShowOptionDialog(null, "New image (ID " + (new ImageLibrary.ByteArray(id)) + ") imported",
480 "Image imported", JOptionPane.OK_OPTION, JOptionPane.WARNING_MESSAGE, null, new String[]{"Dismiss"},
481 "Dismiss");
482 window.dispose();
486 public void actionPerformed(ActionEvent evt)
488 String command = evt.getActionCommand();
489 if("IMPORT".equals(command)) {
490 feedback.setText("Importing disk...");
491 importDisk.setEnabled(false);
492 cancel.setEnabled(false);
493 try {
494 importDisk();
495 } catch(Exception e) {
496 errorDialog(e, "Error making image", window, "Dismiss");
497 cancel.setEnabled(true);
498 keyTyped(null);
500 } else if("CANCEL".equals(command)) {
501 window.dispose();
502 } else {
503 keyTyped(null);
507 public void keyPressed(KeyEvent event)
509 keyTyped(event);
512 public void keyReleased(KeyEvent event)
514 keyTyped(event);
517 private void updateFile()
519 String _filename = imageFile.getText();
520 if(!"".equals(_filename)) {
521 String firstType = null;
522 File fileObject = new File(_filename);
523 if(fileObject.exists() && fileObject.isFile()) {
524 fileSelected = true;
525 directorySelected = false;
526 fileSelectedLength = fileObject.length();
527 if(fileCase == fileSelectedLength)
528 return;
529 fileCase = fileSelectedLength;
530 imageType.removeAllItems();
531 if(fileSelectedLength > 0 && fileSelectedLength <= 262144) {
532 imageType.addItem(BIOS);
533 if(firstType == null)
534 firstType = BIOS;
536 if(fileObject.length() > 0 && (fileObject.length() % 512) == 0) {
537 imageType.addItem(FLOPPY);
538 imageType.addItem(HDD);
539 imageType.addItem(CDROM);
540 if(firstType == null)
541 firstType = FLOPPY;
544 if(fileObject.exists() && fileObject.isDirectory()) {
545 if(fileCase == -2)
546 return;
547 fileCase = -2;
548 fileSelected = false;
549 directorySelected = true;
550 imageType.removeAllItems();
551 imageType.addItem(FLOPPY);
552 imageType.addItem(HDD);
553 if(firstType == null)
554 firstType = FLOPPY;
556 if(firstType != null) {
557 imageType.setSelectedItem(firstType);
558 imageType.setEnabled(true);
559 } else {
560 if(fileCase == -3)
561 return;
562 fileCase = -3;
563 fileSelected = false;
564 directorySelected = false;
565 setNoValidChoice(imageType);
567 } else {
568 if(fileCase == -4)
569 return;
570 fileCase = -4;
571 fileSelected = false;
572 directorySelected = false;
573 setNoValidChoice(imageType);
577 public void keyTyped(KeyEvent event)
579 if(!constructed)
580 return;
582 updateFile();
583 changeGeometry();
585 if(directorySelected) {
586 createTimeLabel.setEnabled(true);
587 volumeLabelLabel.setEnabled(true);
588 if(createTimeLabel.isSelected())
589 createTime.setEnabled(true);
590 else
591 createTime.setEnabled(false);
592 if(volumeLabelLabel.isSelected())
593 volumeLabel.setEnabled(true);
594 else
595 volumeLabel.setEnabled(false);
596 } else {
597 volumeLabel.setEnabled(false);
598 volumeLabelLabel.setEnabled(false);
599 createTime.setEnabled(false);
600 createTimeLabel.setEnabled(false);
603 revalidateForm();
604 window.pack();
607 private int textToInt(String text)
609 if(text == null)
610 return -1;
611 try {
612 int v = Integer.parseInt(text);
613 if(v <= 0)
614 return -1;
615 return v;
616 } catch(NumberFormatException e) {
617 return -1;
621 //40, 41, 42, 43 tracks, 1 sides, 1-15 sectors (up to 320kB).
623 private boolean stdGeometryValid(long len)
625 if((len % 512) != 0)
626 return false;
627 if(len < 320 * 1024 && (len % 20480) != 0)
628 return true; //40 tracks, single sided.
629 if(len < 320 * 1024 && (len % 20992) != 0)
630 return true; //41 tracks, single sided.
631 if(len < 320 * 1024 && (len % 21504) != 0)
632 return true; //42 tracks, single sided.
633 if(len < 320 * 1024 && (len % 22016) != 0)
634 return true; //43 tracks, single sided.
635 if(len < 320 * 1024)
636 return false; //Cutoff for single-sided.
637 if(len < 720 * 1024 && (len % 40960) != 0)
638 return true; //40 tracks, double sided.
639 if(len < 720 * 1024 && (len % 41984) != 0)
640 return true; //41 tracks, double sided.
641 if(len < 720 * 1024 && (len % 43008) != 0)
642 return true; //42 tracks, double sided.
643 if(len < 720 * 1024 && (len % 44032) != 0)
644 return true; //43 tracks, double sided.
645 if(len < 320 * 1024)
646 return false; //Cutoff for 40 tracks double sided.
647 if(len > 4079616)
648 return false; //exceeds 83 tracks, 48 sectors double sided.
649 if((len % 81920) != 0)
650 return true; //80 tracks, double sided.
651 if((len % 82944) != 0)
652 return true; //81 tracks, double sided.
653 if((len % 83968) != 0)
654 return true; //82 tracks, double sided.
655 if((len % 84992) != 0)
656 return true; //83 tracks, double sided.
657 return false;
660 private int stdGeometrySides(long len)
662 if(len < 320 * 1024)
663 return 1;
664 else
665 return 2;
668 private int getSides()
670 String type = (String)imageType.getSelectedItem();
671 if(FLOPPY.equals(type)) {
672 if(stdGeometry.isEnabled() && stdGeometry.isSelected())
673 return stdGeometrySides(fileSelectedLength);
674 return doublesided.isSelected() ? 2 : 1;
675 } else if(HDD.equals(type)) {
676 return textToInt(sides.getText());
677 } else
678 return -1;
681 private boolean forceSides()
683 String type = (String)imageType.getSelectedItem();
684 if(HDD.equals(type))
685 return false;
686 return true;
689 private long sideSectors(long len)
691 if(len < 320 * 1024)
692 return len / 512;
693 else
694 return len / 1024;
697 private int stdGeometrySectors(long len)
699 long sideSects = sideSectors(len);
700 int baseTracks = 80;
701 if(sideSects < 720)
702 baseTracks = 40;
703 for(int i = 0; i < 4; i++) {
704 if(((int)sideSects % (baseTracks + i)) == 0)
705 return (int)sideSects / (baseTracks + i);
707 return -1;
710 private int getSectors()
712 String type = (String)imageType.getSelectedItem();
713 if(stdGeometry.isEnabled() && stdGeometry.isSelected())
714 return stdGeometrySectors(fileSelectedLength);
715 if(HDD.equals(type) || FLOPPY.equals(type))
716 return textToInt(sectors.getText());
717 else
718 return -1;
721 private boolean forceSectors()
723 String type = (String)imageType.getSelectedItem();
724 if(stdGeometry.isEnabled() && stdGeometry.isSelected())
725 return true;
726 if(HDD.equals(type) || FLOPPY.equals(type))
727 return false;
728 return true;
731 private int stdGeometryTracks(long len)
733 long sideSects = sideSectors(len);
734 int baseTracks = 80;
735 if(sideSects < 720)
736 baseTracks = 40;
737 for(int i = 0; i < 4; i++) {
738 if(((int)sideSects % (baseTracks + i)) == 0)
739 return baseTracks + i;
741 return -1;
744 private int getTracks()
746 String type = (String)imageType.getSelectedItem();
747 if(!HDD.equals(type) && !FLOPPY.equals(type))
748 return -1;
749 if(stdGeometry.isEnabled() && stdGeometry.isSelected())
750 return stdGeometryTracks(fileSelectedLength);
751 if(directorySelected)
752 return textToInt(tracks.getText());
753 else if(fileSelected) {
754 int trackBound = 256;
755 if(HDD.equals(type))
756 trackBound = 1024;
757 if((fileSelectedLength % 512) != 0)
758 return -2;
759 long totalSectors = fileSelectedLength / 512;
760 if((totalSectors % getSides()) != 0)
761 return -2;
762 totalSectors /= getSides();
763 if((totalSectors % getSectors()) != 0)
764 return -2;
765 totalSectors /= getSectors();
766 if(totalSectors < 1 || totalSectors > trackBound)
767 return -2;
768 return (int)totalSectors;
769 } else {
770 return -1;
774 private boolean forceTracks()
776 String type = (String)imageType.getSelectedItem();
777 if(!HDD.equals(type) && !FLOPPY.equals(type))
778 return true;
779 if(stdGeometry.isEnabled() && stdGeometry.isSelected())
780 return true;
781 if(directorySelected)
782 return false;
783 return true;
786 private void changeGeometry()
788 String type = (String)imageType.getSelectedItem();
789 if(FLOPPY.equals(type) && fileSelected)
790 stdGeometry.setEnabled(stdGeometryValid(fileSelectedLength));
791 else
792 stdGeometry.setEnabled(false);
793 if(FLOPPY.equals(type) && !stdGeometry.isSelected())
794 doublesided.setEnabled(true);
795 else
796 doublesided.setEnabled(false);
798 if(forceSides()) {
799 sides.setVisible(false);
800 sidesFixed.setVisible(true);
801 int x = getSides();
802 if(x >= 0)
803 sidesFixed.setText("" + x);
804 else if(x == -1)
805 sidesFixed.setText("N/A");
806 else
807 sidesFixed.setText("Unsatisfiable");
808 } else {
809 sides.setVisible(true);
810 sidesFixed.setVisible(false);
813 if(forceSectors()) {
814 sectors.setVisible(false);
815 sectorsFixed.setVisible(true);
816 int x = getSectors();
817 if(x >= 0)
818 sectorsFixed.setText("" + x);
819 else if(x == -1)
820 sectorsFixed.setText("N/A");
821 else
822 sectorsFixed.setText("Unsatisfiable");
823 } else {
824 sectors.setVisible(true);
825 sectorsFixed.setVisible(false);
828 if(forceTracks()) {
829 tracks.setVisible(false);
830 tracksFixed.setVisible(true);
831 int x = getTracks();
832 if(x >= 0)
833 tracksFixed.setText("" + x);
834 else if(x == -1)
835 tracksFixed.setText("N/A");
836 else
837 tracksFixed.setText("Unsatisfiable");
838 } else {
839 tracks.setVisible(true);
840 tracksFixed.setVisible(false);