ciderpress/linux/SSTAsm.cpp
2007-03-27 17:47:10 +00:00

326 lines
8.7 KiB
C++

/*
* CiderPress
* Copyright (C) 2007 by faddenSoft, LLC. All Rights Reserved.
* See the file LICENSE for distribution terms.
*/
/*
* Reassemble SST disk images into a .NIB file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "../diskimg/DiskImg.h"
using namespace DiskImgLib;
#define nil NULL
#if 0
inline int
ConvOddEven(unsigned char val1, unsigned char val2)
{
return ((val1 & 0x55) << 1) | (val2 & 0x55);
}
#endif
const int kSSTNumTracks = 35;
const int kSSTTrackLen = 6656; // or 6384 for .NB2
/*
* Compute the destination file offset for a particular source track. The
* track number ranges from 0 to 69 inclusive. Sectors from two adjacent
* "cooked" tracks are combined into a single "raw nibbilized" track.
*
* The data is ordered like this:
* track 1 sector 15 --> track 1 sector 4 (12 sectors)
* track 0 sector 13 --> track 0 sector 0 (14 sectors)
*
* Total of 26 sectors, or $1a00 bytes.
*/
long
GetBufOffset(int track)
{
assert(track >= 0 && track < kSSTNumTracks*2);
long offset;
if (track & 0x01) {
/* odd, use start of data */
offset = (track / 2) * kSSTTrackLen;
} else {
/* even, start of data plus 12 sectors */
offset = (track / 2) * kSSTTrackLen + 12 * 256;
}
assert(offset >= 0 && offset < kSSTTrackLen * kSSTNumTracks);
return offset;
}
/*
* Copy 17.5 tracks of data from the SST image to a .NIB image.
*
* Data is stored in all 16 sectors of track 0, followed by the first
* 12 sectors of track 1, then on to track 2. Total of $1a00 bytes.
*/
int
LoadSSTData(DiskImg* pDiskImg, int seqNum, unsigned char* trackBuf)
{
DIError dierr;
char sctBuf[256];
int track, sector;
long bufOffset;
for (track = 0; track < kSSTNumTracks; track++) {
int virtualTrack = track + (seqNum * kSSTNumTracks);
bufOffset = GetBufOffset(virtualTrack);
//fprintf(stderr, "USING offset=%ld (track=%d / %d)\n",
// bufOffset, track, virtualTrack);
if (virtualTrack & 0x01) {
/* odd-numbered track, sectors 15-4 */
for (sector = 15; sector >= 4; sector--) {
dierr = pDiskImg->ReadTrackSector(track, sector, sctBuf);
if (dierr != kDIErrNone) {
fprintf(stderr, "ERROR: on track=%d sector=%d\n",
track, sector);
return -1;
}
memcpy(trackBuf + bufOffset, sctBuf, 256);
bufOffset += 256;
}
} else {
for (sector = 13; sector >= 0; sector--) {
dierr = pDiskImg->ReadTrackSector(track, sector, sctBuf);
if (dierr != kDIErrNone) {
fprintf(stderr, "ERROR: on track=%d sector=%d\n",
track, sector);
return -1;
}
memcpy(trackBuf + bufOffset, sctBuf, 256);
bufOffset += 256;
}
}
}
#if 0
int i;
for (i = 0; (size_t) i < sizeof(trackBuf)-10; i++) {
if ((trackBuf[i] | 0x80) == 0xd5 &&
(trackBuf[i+1] | 0x80) == 0xaa &&
(trackBuf[i+2] | 0x80) == 0x96)
{
fprintf(stderr, "off=%5d vol=%d trk=%d sct=%d chk=%d\n", i,
ConvOddEven(trackBuf[i+3], trackBuf[i+4]),
ConvOddEven(trackBuf[i+5], trackBuf[i+6]),
ConvOddEven(trackBuf[i+7], trackBuf[i+8]),
ConvOddEven(trackBuf[i+9], trackBuf[i+10]));
i += 10;
if ((size_t)i < sizeof(trackBuf)-3) {
fprintf(stderr, " 0x%02x 0x%02x 0x%02x\n",
trackBuf[i+1], trackBuf[i+2], trackBuf[i+3]);
}
}
}
#endif
return 0;
}
/*
* Copy sectors from a single image.
*/
int
HandleSSTImage(const char* fileName, int seqNum, unsigned char* trackBuf)
{
DIError dierr;
DiskImg diskImg;
int result = -1;
fprintf(stderr, "Handling '%s'\n", fileName);
dierr = diskImg.OpenImage(fileName, '/', true);
if (dierr != kDIErrNone) {
fprintf(stderr, "ERROR: unable to open '%s'\n", fileName);
goto bail;
}
dierr = diskImg.AnalyzeImage();
if (dierr != kDIErrNone) {
fprintf(stderr, "ERROR: image analysis failed\n");
goto bail;
}
if (diskImg.GetSectorOrder() == DiskImg::kSectorOrderUnknown) {
fprintf(stderr, "ERROR: sector order not set\n");
goto bail;
}
if (diskImg.GetFSFormat() != DiskImg::kFormatUnknown) {
fprintf(stderr, "WARNING: file format *was* recognized!\n");
goto bail;
}
if (diskImg.GetNumTracks() != kSSTNumTracks ||
diskImg.GetNumSectPerTrack() != 16)
{
fprintf(stderr, "ERROR: only 140K floppies can be SST inputs\n");
goto bail;
}
dierr = diskImg.OverrideFormat(diskImg.GetPhysicalFormat(),
DiskImg::kFormatGenericDOSOrd, diskImg.GetSectorOrder());
if (dierr != kDIErrNone) {
fprintf(stderr, "ERROR: format override failed\n");
goto bail;
}
/*
* We have the image open successfully, now do something with it.
*/
result = LoadSSTData(&diskImg, seqNum, trackBuf);
bail:
return result;
}
/*
* Run through the data, adding 0x80 everywhere and re-aligning the
* tracks so that the big clump of sync bytes is at the end.
*/
int
ProcessTrackData(unsigned char* trackBuf)
{
unsigned char* trackPtr;
int track;
for (track = 0, trackPtr = trackBuf; track < kSSTNumTracks;
track++, trackPtr += kSSTTrackLen)
{
bool inRun;
int start = 0;
int longestStart = -1;
int count7f = 0;
int longest = -1;
int i;
inRun = false;
for (i = 0; i < kSSTTrackLen; i++) {
if (trackPtr[i] == 0x7f) {
if (inRun) {
count7f++;
} else {
count7f = 1;
start = i;
inRun = true;
}
} else {
if (inRun) {
if (count7f > longest) {
longest = count7f;
longestStart = start;
}
inRun = false;
} else {
/* do nothing */
}
}
trackPtr[i] |= 0x80;
}
if (longest == -1) {
fprintf(stderr, "HEY: couldn't find any 0x7f in track %d\n",
track);
} else {
fprintf(stderr, "Found run of %d at %d in track %d\n",
longest, longestStart, track);
int bkpt = longestStart + longest;
assert(bkpt < kSSTTrackLen);
char oneTrack[kSSTTrackLen];
memcpy(oneTrack, trackPtr, kSSTTrackLen);
/* copy it back so sync bytes are at end of track */
memcpy(trackPtr, oneTrack + bkpt, kSSTTrackLen - bkpt);
memcpy(trackPtr + (kSSTTrackLen - bkpt), oneTrack, bkpt);
}
}
return 0;
}
/*
* Read sectors from file1 and file2, and write them in the correct
* sequence to outfp.
*/
int
ReassembleSST(const char* file1, const char* file2, FILE* outfp)
{
unsigned char* trackBuf = nil;
int result;
trackBuf = new unsigned char[kSSTNumTracks * kSSTTrackLen];
if (trackBuf == nil) {
fprintf(stderr, "ERROR: malloc failed\n");
return -1;
}
result = HandleSSTImage(file1, 0, trackBuf);
if (result != 0)
return result;
result = HandleSSTImage(file2, 1, trackBuf);
if (result != 0)
return result;
result = ProcessTrackData(trackBuf);
fprintf(stderr, "Writing %d bytes\n", kSSTNumTracks * kSSTTrackLen);
fwrite(trackBuf, 1, kSSTNumTracks * kSSTTrackLen, outfp);
delete[] trackBuf;
return result;
}
/*
* Handle a debug message from the DiskImg library.
*/
/*static*/ void
MsgHandler(const char* file, int line, const char* msg)
{
assert(file != nil);
assert(msg != nil);
fprintf(stderr, "%s", msg);
}
/*
* Parse args, go.
*/
int
main(int argc, char** argv)
{
int result;
if (argc != 3) {
fprintf(stderr, "Usage: %s file1 file2 > outfile\n", argv[0]);
exit(2);
}
Global::SetDebugMsgHandler(MsgHandler);
Global::AppInit();
result = ReassembleSST(argv[1], argv[2], stdout);
Global::AppCleanup();
exit(result != 0);
}