mirror of
https://github.com/fadden/ciderpress.git
synced 2024-11-19 01:09:09 +00:00
326 lines
8.7 KiB
C++
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);
|
||
|
}
|
||
|
|