/* SectorDiskImage.java (c) 2010-2013 Edward Swartz All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0 which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html */ package v9t9.engine.files.image; import java.io.File; import java.io.IOException; import java.text.MessageFormat; import java.util.ArrayList; import java.util.Collections; import v9t9.common.client.ISettingsHandler; import v9t9.common.files.IdMarker; import v9t9.engine.dsr.realdisk.CRC16; import v9t9.engine.dsr.realdisk.ICRCAlgorithm; public class SectorDiskImage extends BaseDiskImage { public SectorDiskImage(ISettingsHandler settings, String name, File file) { super(name, file, settings); } /* (non-Javadoc) * @see v9t9.emulator.hardware.dsrs.realdisk.BaseDiskImage#getDiskType() */ @Override public String getDiskType() { return "sector-image"; } /* (non-Javadoc) * @see v9t9.emulator.hardware.dsrs.realdisk.BaseDiskImage#getDefaultTrackSize() */ @Override public short getDefaultTrackSize() { return 256 * 9; } @Override public void writeImageHeader() throws IOException { if (getHandle() == null || readonly) { return; } // no explicit header /* maintain invariants */ growImageForContent(); } @Override public void readImageHeader() throws IOException { long sz; byte sector[] = new byte[256]; if (getHandle() == null) return; readonly |= !spec.canWrite(); /* no header: guess */ sz = getHandle().length(); if (sz < 256) throw new IOException("Disk size for '" + spec + "' is too small to be a disk file: " + sz); /* read sector 0 */ getHandle().seek(0); getHandle().read(sector); hdr.setTracks(sector[0x11] & 0xff); hdr.setSides(sector[0x12] & 0xff); hdr.setTrackSize((sector[0x0C] * 256)); hdr.setSecsPerTrack(sector[0x0C]); hdr.setTrack0Offset(0); if ((hdr.getTracks() <= 0 || hdr.getSides() <= 0 || hdr.getTrackSize() <= 0) || 'D' != sector[0x0D] || 'S' != sector[0x0E] || 'K' != sector[0x0F]) { // hmm... bogus or unformatted disk -- guess hdr.setSides(1); hdr.setTrackSize(256*9); int tracks = (int) (sz / hdr.getTrackSize()); hdr.setTracks(tracks); hdr.setSecsPerTrack(9); if (tracks >= 80) { tracks /= 2; hdr.setTracks(tracks); hdr.setSides(hdr.getSides() + 1); if (tracks >= 80) { tracks /= 2; hdr.setTracks(tracks); hdr.setSecsPerTrack(hdr.getSecsPerTrack() << 1); hdr.setTrackSize(hdr.getTrackSize() << 1); if (tracks > 40) { hdr.setTracks(40); } } } } hdr.setSide2DirectionKnown(false); if (hdr.getTrackSize() > RealDiskConsts.DSKbuffersize) { throw new IOException(MessageFormat.format("Disk image has too large track size ({0} > {1})", hdr.getTrackSize(), RealDiskConsts.DSKbuffersize)); } } /* (non-Javadoc) * @see v9t9.emulator.hardware.dsrs.realdisk.BaseDiskImage#getHeaderSize() */ @Override public int getHeaderSize() { return 0; } /** * @param rwBuffer * @param start * @param buflen * @param dataoffset */ @Override public void writeSectorData(byte[] rwBuffer, int start, int buflen, IdMarker marker) { try { System.arraycopy(rwBuffer, 0, trackBuffer, marker.dataoffset + 1, buflen); } catch (IndexOutOfBoundsException e) { e.printStackTrace(); } trackChanged = true; // dump contents RealDiskUtils.dumpBuffer(dumper, rwBuffer, start, buflen); } @Override public void writeTrackData(byte[] rwBuffer, int start, int buflen) { super.writeTrackData(rwBuffer, start, buflen); int expSecs = hdr.getTrackSize()/256; if (trackMarkers == null || trackMarkers.size() != expSecs) { dumper.error("Program is formatting track at {1} on ''{0}'' with non-ordinary sectors; " + "this does not work with sector-image disks", spec, Long.toHexString(getTrackDiskOffset())); } // extract only sector data for (IdMarker marker : trackMarkers) { if (marker.sizeid == 1 && marker.sectorid < 18) { try { System.arraycopy(rwBuffer, marker.dataoffset+1, trackBuffer, marker.sectorid*256, 256); } catch (IndexOutOfBoundsException e) { e.printStackTrace(); } } } } /** * Scan the current track for ID markers * @return */ @Override public void fetchFormatAndTrackMarkers() { try { readCurrentTrackData(); } catch (IOException e) { dumper.error(e.getMessage()); trackFormat = fmFormat; trackMarkers = Collections.emptyList(); return; } /* easy */ trackMarkers = new ArrayList<IdMarker>(); int sizeid = 1; // HACK int sectorsize = (128 << sizeid); ICRCAlgorithm crcAlg = new CRC16(0x1021); for (int dataoffset = 0; dataoffset < hdr.getTrackSize(); dataoffset += sectorsize) { IdMarker marker = new IdMarker(); crcAlg.reset(); marker.idCode = (byte) 0xfe; marker.dataCode = (byte) 0xfb; marker.idoffset = -1; marker.dataoffset = dataoffset - 1; marker.trackid = (byte) track; marker.sectorid = (byte) (dataoffset / sectorsize); marker.sideid = (byte) side; marker.sizeid = (byte) sizeid; crcAlg.feed(marker.idCode); crcAlg.feed(marker.trackid); crcAlg.feed(marker.sideid); crcAlg.feed(marker.sectorid); crcAlg.feed(marker.sizeid); marker.crcid = crcAlg.read(); trackMarkers.add(marker); } } /** * @param currentMarker * @param rwBuffer * @param i * @param buflen */ @Override public void readSectorData(IdMarker currentMarker, byte[] rwBuffer, int i, int buflen) { System.arraycopy(trackBuffer, currentMarker.dataoffset + 1, rwBuffer, 0, buflen); RealDiskUtils.dumpBuffer(dumper, rwBuffer, 0, 256); } /* (non-Javadoc) * @see v9t9.engine.files.image.BaseDiskImage#discoverSide2TrackOrdering() */ @Override protected void discoverSide2TrackOrdering() { hdr.setInvertedSide2(true); hdr.setSide2DirectionKnown(true); } }