/*
FMFormat.java
(c) 2013-2014 Ed 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.util.ArrayList;
import java.util.List;
import v9t9.common.files.IdMarker;
import v9t9.engine.Dumper;
import v9t9.engine.dsr.realdisk.CRC16;
import v9t9.engine.dsr.realdisk.ICRCAlgorithm;
import ejs.base.utils.HexUtils;
/**
* @author ejs
*
*/
public class FMFormat implements IDiskFormat {
private static final byte ID_MARK = (byte) 0xfe;
private static final byte DATA_MARK = (byte) 0xfb;
private CRC16 crcAlg;
private Dumper dumper;
/**
*
*/
public FMFormat(Dumper dumper) {
this.dumper = dumper;
crcAlg = new CRC16(0x1021);
}
/* (non-Javadoc)
* @see v9t9.engine.files.image.IDiskFormat#getCRCAlgorithm()
*/
@Override
public ICRCAlgorithm getCRCAlgorithm() {
return crcAlg;
}
/* (non-Javadoc)
* @see v9t9.engine.files.image.IDiskFormat#fetchIdMarkers(byte[], v9t9.common.files.IDiskHeader)
*/
@Override
public List<IdMarker> fetchIdMarkers(byte[] trackBuffer, int trackSize, boolean formatting) {
List<IdMarker> markers = new ArrayList<IdMarker>();
int ffCount = 0;
for (int startoffset = 0; startoffset < trackSize; startoffset++) {
byte b = trackBuffer[startoffset];
if (b == (byte) 0xff) {
ffCount++;
continue;
}
if (b != ID_MARK)
continue;
if (ffCount < 12 && startoffset >= 32) {
ffCount = 0;
continue;
}
CircularByteIter iter = new CircularByteIter(trackBuffer, trackSize);
iter.setPointers(0, startoffset);
iter.setCount(30);
IdMarker marker = new IdMarker();
marker.idoffset = iter.getPointer() + iter.getStart();
crcAlg.reset();
// get ID
marker.idCode = iter.next();
marker.trackid = iter.next();
marker.sideid = iter.next();
marker.sectorid = iter.next();
marker.sizeid = iter.next();
marker.crcid = (short) (iter.next()<<8); marker.crcid |= iter.next() & 0xff;
marker.dataCode = DATA_MARK;
crcAlg.feed(marker.idCode);
crcAlg.feed(marker.trackid);
crcAlg.feed(marker.sideid);
crcAlg.feed(marker.sectorid);
crcAlg.feed(marker.sizeid);
boolean matched = marker.crcid == (short) 0xf7f7; // marker for 'please calculate CRC for me'
if (!matched) {
short crc = crcAlg.read();
if (formatting) {
crcAlg.feed((byte) (crc >> 8));
crcAlg.feed((byte) (crc & 0xff));
if (crcAlg.read() != 0) {
dumper.info("FDCfindIDmarker: failed ID CRC check on format (>{0} != >{1})",
HexUtils.toHex4(crcAlg.read()), HexUtils.toHex4(0));
continue;
}
marker.crcid = crc;
trackBuffer[marker.idoffset + 1 + 4] = (byte) (crc >> 8);
trackBuffer[marker.idoffset + 1 + 5] = (byte) (crc & 0xff);
}
if (crc != marker.crcid)
{
dumper.info("FDCfindIDmarker: failed ID CRC check (>{0} != >{1})",
HexUtils.toHex4(marker.crcid), HexUtils.toHex4(crc));
continue;
}
}
// look ahead to see if we find a data marker
boolean foundAnotherId = false;
while (iter.hasNext() && iter.peek() != DATA_MARK) {
if (iter.peek() == ID_MARK) {
foundAnotherId = true;
break;
}
iter.next();
}
// we probably started inside data
if (foundAnotherId)
continue;
if (iter.hasNext() && marker.sideid >= 0) {
marker.dataoffset = iter.getPointer() + iter.getStart();
markers.add(marker);
}
}
return markers;
}
/* (non-Javadoc)
* @see v9t9.engine.files.image.IDiskFormat#doesFormatMatch()
*/
@Override
public boolean doesFormatMatch(byte[] trackBuffer, int trackSize) {
IdMarker marker = new IdMarker();
int ffCount = 0;
int secCount = 0;
for (int startoffset = 0; startoffset < trackSize; startoffset++) {
byte b = trackBuffer[startoffset];
if (b == (byte) 0xff) {
ffCount++;
continue;
}
if (b != ID_MARK)
continue;
if (ffCount < 12 && startoffset >= 16) {
ffCount = 0;
continue;
}
CircularByteIter iter = new CircularByteIter(trackBuffer, trackSize);
iter.setPointers(0, startoffset);
iter.setCount(30);
marker.idoffset = iter.getPointer() + iter.getStart();
crcAlg.reset();
marker.idCode = iter.next();
marker.trackid = iter.next();
marker.sideid = iter.next();
marker.sectorid = iter.next();
marker.sizeid = iter.next();
marker.crcid = (short) (iter.next()<<8); marker.crcid |= iter.next() & 0xff;
marker.dataCode = DATA_MARK;
crcAlg.feed(marker.idCode);
crcAlg.feed(marker.trackid);
crcAlg.feed(marker.sideid);
crcAlg.feed(marker.sectorid);
crcAlg.feed(marker.sizeid);
boolean matched = marker.crcid == (short) 0xf7f7; // marker for 'please calculate CRC for me'
if (!matched) {
short crc = crcAlg.read();
if (crc == marker.crcid)
matched = true;
}
if (!matched) {
continue;
}
secCount++;
while (iter.hasNext() && iter.peek() != DATA_MARK) {
iter.next();
}
if (iter.hasNext())
marker.dataoffset = iter.getPointer() + iter.getStart();
else
marker.dataoffset = -1;
}
return secCount > 0;
}
}