mirror of
https://github.com/markdavidlong/AppleSAWS.git
synced 2024-12-21 07:29:23 +00:00
Initial push of pre-existing code.
This commit is contained in:
parent
2d532c386b
commit
1bf321072d
42
src/AppleSAWS.pro
Normal file
42
src/AppleSAWS.pro
Normal file
@ -0,0 +1,42 @@
|
||||
|
||||
QT += core gui
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
TARGET = AppleSAWS
|
||||
TEMPLATE = app
|
||||
|
||||
SOURCES += main.cpp \
|
||||
diskfile.cxx \
|
||||
sector.cxx \
|
||||
vtoc.cxx \
|
||||
catalogsector.cxx \
|
||||
applestring.cxx \
|
||||
tracksectorlist.cxx \
|
||||
filedescriptiveentry.cxx \
|
||||
applesoftfile.cxx \
|
||||
genericfile.cxx \
|
||||
disassembler.cxx \
|
||||
binaryfile.cxx \
|
||||
catalogwidget.cxx \
|
||||
mainwindow.cxx
|
||||
|
||||
HEADERS += \
|
||||
diskfile.h \
|
||||
sector.h \
|
||||
vtoc.h \
|
||||
util.h \
|
||||
catalogsector.h \
|
||||
applestring.h \
|
||||
tracksectorlist.h \
|
||||
filedescriptiveentry.h \
|
||||
applesoftfile.h \
|
||||
genericfile.h \
|
||||
disassembler.h \
|
||||
binaryfile.h \
|
||||
catalogwidget.h \
|
||||
mainwindow.h
|
||||
|
||||
FORMS += \
|
||||
catalogwidget.ui \
|
||||
mainwindow.ui
|
195
src/applesoftfile.cxx
Normal file
195
src/applesoftfile.cxx
Normal file
@ -0,0 +1,195 @@
|
||||
#include "applesoftfile.h"
|
||||
#include <QDebug>
|
||||
|
||||
ApplesoftFile::ApplesoftFile(QByteArray data) : GenericFile(data)
|
||||
{
|
||||
if (m_tokens.size() == 0)
|
||||
{
|
||||
makeTokens();
|
||||
}
|
||||
|
||||
if (!data.isEmpty())
|
||||
{
|
||||
setData(data);
|
||||
}
|
||||
}
|
||||
|
||||
void ApplesoftFile::setData(QByteArray data)
|
||||
{
|
||||
GenericFile::setData(data);
|
||||
|
||||
quint8 addlo = m_data.at(0);
|
||||
quint8 addhi = m_data.at(1);
|
||||
m_length = addlo + (addhi * 256);
|
||||
m_data.remove(0,2);
|
||||
m_detokenized = detokenize();
|
||||
}
|
||||
|
||||
QList<ApplesoftLine> ApplesoftFile::detokenize()
|
||||
{
|
||||
QList<ApplesoftLine> retval;
|
||||
|
||||
/*
|
||||
qDebug() << "Length: " << m_length;
|
||||
for (int idx = 0; idx < m_length; idx += 8)
|
||||
{
|
||||
qDebug()
|
||||
<< QString("%1 (%2): %3 %4 %5 %6 %7 %8 %9 %10")
|
||||
.arg((quint16) idx + 0x801,4,16,QChar('0')).toUpper()
|
||||
.arg((quint16) idx + 0x801,4,10,QChar('0'))
|
||||
.arg((quint8) m_data[idx],2,16,QChar('0')).toUpper()
|
||||
.arg((quint8) m_data[idx+1],2,16,QChar('0')).toUpper()
|
||||
.arg((quint8) m_data[idx+2],2,16,QChar('0')).toUpper()
|
||||
.arg((quint8) m_data[idx+3],2,16,QChar('0')).toUpper()
|
||||
.arg((quint8) m_data[idx+4],2,16,QChar('0')).toUpper()
|
||||
.arg((quint8) m_data[idx+5],2,16,QChar('0')).toUpper()
|
||||
.arg((quint8) m_data[idx+6],2,16,QChar('0')).toUpper()
|
||||
.arg((quint8) m_data[idx+7],2,16,QChar('0')).toUpper();
|
||||
|
||||
}
|
||||
*/
|
||||
int idx = 0;
|
||||
quint8 val = 0;
|
||||
while (idx < m_data.length()) {
|
||||
ApplesoftLine line;
|
||||
line.next_address = (quint8) m_data[idx] + (((quint8) m_data[idx+1]) *256);
|
||||
line.tokens.append(m_data[idx]);
|
||||
line.tokens.append(m_data[idx+1]);
|
||||
idx++; idx++;
|
||||
line.linenum = (quint8) m_data[idx] + (((quint8) m_data[idx+1])*256);
|
||||
line.tokens.append(m_data[idx]);
|
||||
line.tokens.append(m_data[idx+1]);
|
||||
idx++; idx++;
|
||||
if (line.next_address == 0x00) { break; }
|
||||
do {
|
||||
val = m_data[idx++];
|
||||
line.tokens.append(val);
|
||||
if (val >= 0x80) {
|
||||
line.detokenized_line.append(" " + m_tokens[val]);
|
||||
} else {
|
||||
if (val >= 0x20) {
|
||||
line.detokenized_line.append(val);
|
||||
} else if (val == 0x7F) {
|
||||
QChar ch = QChar(0x2401);
|
||||
line.detokenized_line.append(ch);
|
||||
}else if (val > 0x00) {
|
||||
QChar ch = QChar(0x00 + val);
|
||||
line.detokenized_line.append(ch);
|
||||
}
|
||||
}
|
||||
} while (val != 0x00);
|
||||
retval.append(line);
|
||||
}
|
||||
|
||||
m_data_end = idx;
|
||||
|
||||
if (idx < m_data.length()) {
|
||||
qDebug() << QString("%1 byte(s) unaccounted for.").arg(m_data.length() - idx);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ApplesoftFile::list() {
|
||||
foreach (ApplesoftLine line,detokenized()) {
|
||||
QString debugline = QString("%1 %2 %3").arg(line.next_address,4,16,QChar('0')).arg(line.linenum).arg(line.detokenized_line);
|
||||
qDebug() << debugline;
|
||||
/*
|
||||
debugline = "";
|
||||
foreach (quint8 val, line.tokens) {
|
||||
debugline.append(QString("%1 ").arg(val,2,16,QChar('0')));
|
||||
}
|
||||
qDebug() << " " << debugline;
|
||||
qDebug() << "\n";
|
||||
*/
|
||||
}
|
||||
|
||||
qDebug() << extraDataHexValues().join("\n");
|
||||
}
|
||||
|
||||
QStringList ApplesoftFile::extraDataHexValues() {
|
||||
QStringList retval;
|
||||
|
||||
QString debugline = "";
|
||||
int count = 0;
|
||||
foreach (quint8 val, extraData()) {
|
||||
debugline.append(QString("%1").arg(val,2,16,QChar('0')).toUpper());
|
||||
count++;
|
||||
if (count == 16) {
|
||||
retval.append(debugline);
|
||||
debugline = "";
|
||||
count = 0;
|
||||
} else {
|
||||
debugline.append(" ");
|
||||
}
|
||||
}
|
||||
if (!debugline.simplified().isEmpty()) {
|
||||
retval.append(debugline);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
QByteArray ApplesoftFile::extraData()
|
||||
{
|
||||
return m_data.mid(m_data_end);
|
||||
}
|
||||
|
||||
void ApplesoftFile::makeTokens()
|
||||
{
|
||||
m_tokens[0x80] = "END "; m_tokens[0x81] = "FOR "; m_tokens[0x82] = "NEXT ";
|
||||
m_tokens[0x83] = "DATA "; m_tokens[0x84] = "INPUT "; m_tokens[0x85] = " DEL ";
|
||||
m_tokens[0x86] = "DIM "; m_tokens[0x87] = "READ "; m_tokens[0x88] = "GR ";
|
||||
m_tokens[0x89] = "TEXT "; m_tokens[0x8A] = "PR# "; m_tokens[0x8B] = "IN# ";
|
||||
m_tokens[0x8C] = "CALL "; m_tokens[0x8D] = "PLOT "; m_tokens[0x8E] = "HLIN ";
|
||||
m_tokens[0x8F] = "VLIN "; m_tokens[0x90] = "HGR2 "; m_tokens[0x91] = "HGR ";
|
||||
m_tokens[0x92] = "HCOLOR= "; m_tokens[0x93] = "HPLOT "; m_tokens[0x94] = "DRAW ";
|
||||
m_tokens[0x95] = "XDRAW "; m_tokens[0x96] = "HTAB "; m_tokens[0x97] = "HOME ";
|
||||
m_tokens[0x98] = "ROT= "; m_tokens[0x99] = "SCALE= "; m_tokens[0x9A] = "SHLOAD ";
|
||||
m_tokens[0x9B] = "TRACE "; m_tokens[0x9C] = "NOTRACE "; m_tokens[0x9D] = "NORMAL ";
|
||||
m_tokens[0x9E] = "INVERSE "; m_tokens[0x9F] = "FLASH "; m_tokens[0xA0] = "COLOR= ";
|
||||
m_tokens[0xA1] = "POP "; m_tokens[0xA2] = "VTAB "; m_tokens[0xA3] = "HIMEM: ";
|
||||
m_tokens[0xA4] = "LOMEM: "; m_tokens[0xA5] = "ONERR "; m_tokens[0xA6] = "RESUME ";
|
||||
m_tokens[0xA7] = "RECALL "; m_tokens[0xA8] = "STORE "; m_tokens[0xA9] = "SPEED= ";
|
||||
m_tokens[0xAA] = "LET "; m_tokens[0xAB] = "GOTO "; m_tokens[0xAC] = "RUN ";
|
||||
m_tokens[0xAD] = "IF "; m_tokens[0xAE] = "RESTORE "; m_tokens[0xAF] = "& ";
|
||||
m_tokens[0xB0] = "GOSUB "; m_tokens[0xB1] = "RETURN "; m_tokens[0xB2] = "REM ";
|
||||
m_tokens[0xB3] = "STOP "; m_tokens[0xB4] = "ON "; m_tokens[0xB5] = "WAIT ";
|
||||
m_tokens[0xB6] = "LOAD "; m_tokens[0xB7] = "SAVE "; m_tokens[0xB8] = "DEF ";
|
||||
m_tokens[0xB9] = "POKE "; m_tokens[0xBA] = "PRINT "; m_tokens[0xBB] = "CONT ";
|
||||
m_tokens[0xBC] = "LIST "; m_tokens[0xBD] = "CLEAR "; m_tokens[0xBE] = "GET ";
|
||||
m_tokens[0xBF] = "NEW "; m_tokens[0xC0] = "TAB "; m_tokens[0xC1] = " TO ";
|
||||
m_tokens[0xC2] = "FN "; m_tokens[0xC3] = "SPC( "; m_tokens[0xC4] = "THEN ";
|
||||
m_tokens[0xC5] = " AT "; m_tokens[0xC6] = "NOT "; m_tokens[0xC7] = " STEP ";
|
||||
m_tokens[0xC8] = "+ "; m_tokens[0xC9] = "- "; m_tokens[0xCA] = "* ";
|
||||
m_tokens[0xCB] = "/ "; m_tokens[0xCC] = "^ "; m_tokens[0xCD] = " AND";
|
||||
m_tokens[0xCE] = " OR"; m_tokens[0xCF] = "> "; m_tokens[0xD0] = "= ";
|
||||
m_tokens[0xD1] = "< "; m_tokens[0xD2] = "SGN "; m_tokens[0xD3] = "INT ";
|
||||
m_tokens[0xD4] = "ABS "; m_tokens[0xD5] = "USR "; m_tokens[0xD6] = "FRE ";
|
||||
m_tokens[0xD7] = "SCRN ( "; m_tokens[0xD8] = "PDL "; m_tokens[0xD9] = "POS ";
|
||||
m_tokens[0xDA] = "SQR "; m_tokens[0xDB] = "RND "; m_tokens[0xDC] = "LOG ";
|
||||
m_tokens[0xDD] = "EXP "; m_tokens[0xDE] = "COS "; m_tokens[0xDF] = "SIN ";
|
||||
m_tokens[0xE0] = "TAN "; m_tokens[0xE1] = "ATN "; m_tokens[0xE2] = "PEEK ";
|
||||
m_tokens[0xE3] = "LEN "; m_tokens[0xE4] = "STR$ "; m_tokens[0xE5] = "VAL ";
|
||||
m_tokens[0xE6] = "ASC "; m_tokens[0xE7] = "CHR$ "; m_tokens[0xE8] = "LEFT$ ";
|
||||
m_tokens[0xE9] = "RIGHT$ "; m_tokens[0xEA] = "MID$ "; m_tokens[0xEB] = "{Token 0xEB} ";
|
||||
m_tokens[0xEC] = "{Token 0xEC} ";
|
||||
m_tokens[0xED] = "{Token 0xED} ";
|
||||
m_tokens[0xEE] = "{Token 0xEE} ";
|
||||
m_tokens[0xEF] = "{Token 0xEF} ";
|
||||
m_tokens[0xF0] = "{Token 0xF0} ";
|
||||
m_tokens[0xF1] = "{Token 0xF1} ";
|
||||
m_tokens[0xF2] = "{Token 0xF2} ";
|
||||
m_tokens[0xF3] = "{Token 0xF3} ";
|
||||
m_tokens[0xF4] = "{Token 0xF4} ";
|
||||
m_tokens[0xF5] = "{Token 0xF5} ";
|
||||
m_tokens[0xF6] = "{Token 0xF6} ";
|
||||
m_tokens[0xF7] = "{Token 0xF7} ";
|
||||
m_tokens[0xF8] = "{Token 0xF8} ";
|
||||
m_tokens[0xF9] = "{Token 0xF9} ";
|
||||
m_tokens[0xFA] = "{Token 0xFA} ";
|
||||
m_tokens[0xFB] = "{Token 0xFB} ";
|
||||
m_tokens[0xFC] = "{Token 0xFC} ";
|
||||
m_tokens[0xFD] = "{Token 0xFD} ";
|
||||
m_tokens[0xFE] = "{Token 0xFE} ";
|
||||
m_tokens[0xFF] = "{Token 0xFF} ";
|
||||
}
|
38
src/applesoftfile.h
Normal file
38
src/applesoftfile.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef APPLESOFTFILE_H
|
||||
#define APPLESOFTFILE_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QStringList>
|
||||
#include <QMap>
|
||||
|
||||
#include "genericfile.h"
|
||||
|
||||
struct ApplesoftLine {
|
||||
quint16 next_address;
|
||||
quint16 linenum;
|
||||
QByteArray tokens;
|
||||
QString detokenized_line;
|
||||
};
|
||||
|
||||
|
||||
class ApplesoftFile : public GenericFile
|
||||
{
|
||||
public:
|
||||
ApplesoftFile(QByteArray data = QByteArray());
|
||||
void setData(QByteArray data);
|
||||
QByteArray extraData();
|
||||
QList<ApplesoftLine> detokenized() { return m_detokenized; }
|
||||
void list();
|
||||
QStringList extraDataHexValues();
|
||||
|
||||
private:
|
||||
void makeTokens();
|
||||
QList<ApplesoftLine> detokenize();
|
||||
|
||||
int m_data_end;
|
||||
QMap<quint8,QString> m_tokens;
|
||||
quint16 m_length;
|
||||
QList<ApplesoftLine> m_detokenized;
|
||||
};
|
||||
|
||||
#endif // APPLESOFTFILE_H
|
78
src/applestring.cxx
Normal file
78
src/applestring.cxx
Normal file
@ -0,0 +1,78 @@
|
||||
#include "applestring.h"
|
||||
|
||||
|
||||
|
||||
QString AppleString::printable() const
|
||||
{
|
||||
QString retval;
|
||||
foreach (quint8 ch, *this) {
|
||||
retval.append(AppleChar(ch).printable());
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
QVector<TextAttribute> AppleString::attributes() const
|
||||
{
|
||||
QVector<TextAttribute> retval(this->length());
|
||||
int idx = 0;
|
||||
foreach (quint8 ch, *this) {
|
||||
retval[idx++] = AppleChar(ch).getAttribute();
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
|
||||
QChar AppleChar::printable() const
|
||||
{
|
||||
quint8 newval;
|
||||
switch (getTextSet()) {
|
||||
case SetInvUC:
|
||||
newval = m_val+0x40;
|
||||
break;
|
||||
case SetInvSp:
|
||||
newval = m_val;
|
||||
break;
|
||||
case SetFlUC:
|
||||
newval = m_val;
|
||||
break;
|
||||
case SetFlSp:
|
||||
newval = m_val-0x40;
|
||||
break;
|
||||
case SetNormUC:
|
||||
newval = m_val-0x40;
|
||||
break;
|
||||
case SetNormSp:
|
||||
newval = m_val-0x80;
|
||||
break;
|
||||
case SetNormAltUC:
|
||||
newval = m_val-0x80;
|
||||
break;
|
||||
case SetNormLC:
|
||||
default:
|
||||
newval = m_val-0x80;
|
||||
break;
|
||||
}
|
||||
return QChar(newval);
|
||||
}
|
||||
|
||||
TextAttribute AppleChar::getAttribute() const
|
||||
{
|
||||
if (m_val <= 0x3f) { return Inverse; }
|
||||
if (m_val <= 0x7f) { return Flash; }
|
||||
if (m_val <= 0xbf) { return Normal; }
|
||||
if (m_val <= 0xdf) { return NormalHigh; }
|
||||
return Normal;
|
||||
}
|
||||
|
||||
TextSet AppleChar::getTextSet() const {
|
||||
if (m_val < 0x20) { return SetInvUC; }
|
||||
if (m_val < 0x40) { return SetInvSp; }
|
||||
if (m_val < 0x60) { return SetFlUC; }
|
||||
if (m_val < 0x80) { return SetFlSp; }
|
||||
if (m_val < 0xA0) { return SetNormUC; }
|
||||
if (m_val < 0xC0) { return SetNormSp; }
|
||||
if (m_val < 0xE0) { return SetNormAltUC; }
|
||||
return SetNormLC;
|
||||
}
|
||||
|
32
src/applestring.h
Normal file
32
src/applestring.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef APPLESTRING_H
|
||||
#define APPLESTRING_H
|
||||
|
||||
#include <QVector>
|
||||
#include <QChar>
|
||||
#include <QString>
|
||||
#include <QByteArray>
|
||||
|
||||
#include "util.h"
|
||||
|
||||
class AppleChar {
|
||||
public:
|
||||
AppleChar() { m_val = 0; }
|
||||
AppleChar(quint8 ch) { m_val = ch; }
|
||||
|
||||
QChar printable() const;
|
||||
|
||||
TextAttribute getAttribute() const;
|
||||
TextSet getTextSet() const;
|
||||
|
||||
private:
|
||||
quint8 m_val;
|
||||
};
|
||||
|
||||
class AppleString : public QByteArray {
|
||||
public:
|
||||
QString printable() const;
|
||||
QVector<TextAttribute> attributes() const;
|
||||
|
||||
};
|
||||
|
||||
#endif // APPLESTRING_H
|
28
src/binaryfile.cxx
Normal file
28
src/binaryfile.cxx
Normal file
@ -0,0 +1,28 @@
|
||||
#include <QDebug>
|
||||
#include "binaryfile.h"
|
||||
|
||||
BinaryFile::BinaryFile(QByteArray data) : GenericFile(data)
|
||||
{
|
||||
m_length = 0;
|
||||
m_address = 0;
|
||||
|
||||
if (!data.isEmpty()) {
|
||||
setData(data);
|
||||
}
|
||||
}
|
||||
|
||||
void BinaryFile::setData(QByteArray data)
|
||||
{
|
||||
if (data.length() >= 4) {
|
||||
QByteArray metadata = data.left(4);
|
||||
m_data = data.mid(4);
|
||||
m_address = (quint8) metadata[0] + ((quint8) metadata[1]*256);
|
||||
m_length = (quint8) metadata[2] + ((quint8) metadata[3]*256);
|
||||
}
|
||||
}
|
||||
|
||||
void BinaryFile::dump()
|
||||
{
|
||||
qDebug() << QString("Address: %1 Length: %2").arg(m_address,4,16,QChar('0')).arg(m_length,4,16,QChar('0')).toUpper();
|
||||
qDebug() << QString("Data Length Recorded: %1").arg(m_data.length(),4,16,QChar('0')).toUpper();
|
||||
}
|
23
src/binaryfile.h
Normal file
23
src/binaryfile.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef BINARYFILE_H
|
||||
#define BINARYFILE_H
|
||||
|
||||
#include "genericfile.h"
|
||||
|
||||
class BinaryFile : public GenericFile
|
||||
{
|
||||
public:
|
||||
BinaryFile(QByteArray data = QByteArray());
|
||||
void setData(QByteArray data);
|
||||
|
||||
quint16 address() { return m_address; }
|
||||
quint16 length() { return m_length; }
|
||||
|
||||
QByteArray data() { return m_data; }
|
||||
void dump();
|
||||
|
||||
protected:
|
||||
quint16 m_address;
|
||||
quint16 m_length;
|
||||
};
|
||||
|
||||
#endif // BINARYFILE_H
|
44
src/catalogsector.cxx
Normal file
44
src/catalogsector.cxx
Normal file
@ -0,0 +1,44 @@
|
||||
#include "catalogsector.h"
|
||||
#include "sector.h"
|
||||
|
||||
CatalogSector::CatalogSector(Sector *data)
|
||||
{
|
||||
m_data = data;
|
||||
|
||||
m_next.track = m_data->rawData()[0x01];
|
||||
m_next.sector = m_data->rawData()[0x02];
|
||||
|
||||
for (int idx = 0; idx<7; idx++)
|
||||
{
|
||||
FileDescriptiveEntry fde = makeFDE(idx*0x23+0x0B);
|
||||
if (fde.firstTSListSector != TSPair(0,0)) {
|
||||
m_fdes.append(fde);
|
||||
// qDebug() << "FDE #"<<idx;
|
||||
// fde.dump();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CatalogSector::dumpFDEs() {
|
||||
for (int idx = 0; idx<7; idx++)
|
||||
{
|
||||
FileDescriptiveEntry fde = m_fdes[idx];
|
||||
if (fde.firstTSListSector != TSPair(0,0)) {
|
||||
qDebug() << "FDE #"<<idx;
|
||||
fde.dump();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileDescriptiveEntry CatalogSector::makeFDE(int offset)
|
||||
{
|
||||
FileDescriptiveEntry fde;
|
||||
fde.firstTSListSector.track = m_data->rawData()[offset + 0x00];
|
||||
fde.firstTSListSector.sector = m_data->rawData()[offset + 0x01];
|
||||
fde.fileTypeAndFlags = m_data->rawData()[offset + 0x02];
|
||||
fde.lengthInSectors = m_data->rawData()[offset + 0x21] + (m_data->rawData()[offset + 0x22] * 256);
|
||||
for (int idx = 0x03; idx <= 0x20; idx++) {
|
||||
fde.filename.append(m_data->rawData()[idx+offset]);
|
||||
}
|
||||
return fde;
|
||||
}
|
43
src/catalogsector.h
Normal file
43
src/catalogsector.h
Normal file
@ -0,0 +1,43 @@
|
||||
#ifndef CATALOGSECTOR_H
|
||||
#define CATALOGSECTOR_H
|
||||
|
||||
#include <Qt>
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
|
||||
#include "util.h"
|
||||
#include "applestring.h"
|
||||
#include "filedescriptiveentry.h"
|
||||
|
||||
class Sector;
|
||||
|
||||
|
||||
|
||||
class CatalogSector
|
||||
{
|
||||
public:
|
||||
CatalogSector(Sector *sector);
|
||||
|
||||
FileDescriptiveEntry &getFDE(quint8 number) {
|
||||
if (number >= m_fdes.length()) {
|
||||
number = m_fdes.length() - 1;
|
||||
}
|
||||
return m_fdes[number];
|
||||
}
|
||||
|
||||
QList<FileDescriptiveEntry> getFDEs() { return m_fdes; }
|
||||
|
||||
TSPair nextCatalogSector() { return m_next; }
|
||||
|
||||
void dumpFDEs();
|
||||
|
||||
private:
|
||||
FileDescriptiveEntry makeFDE(int offset);
|
||||
|
||||
private:
|
||||
Sector *m_data;
|
||||
QList<FileDescriptiveEntry> m_fdes;
|
||||
TSPair m_next;
|
||||
};
|
||||
|
||||
#endif // CATALOGSECTOR_H
|
61
src/catalogwidget.cxx
Normal file
61
src/catalogwidget.cxx
Normal file
@ -0,0 +1,61 @@
|
||||
#include "catalogwidget.h"
|
||||
#include "ui_catalogwidget.h"
|
||||
#include "filedescriptiveentry.h"
|
||||
#include <QUrl>
|
||||
|
||||
CatalogWidget::CatalogWidget(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::CatalogWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->catalog_list->setFont(QFont("monospace"));
|
||||
|
||||
}
|
||||
|
||||
CatalogWidget::~CatalogWidget()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void CatalogWidget::prepForNewDisk(QString filename, DiskFile *disk)
|
||||
{
|
||||
m_disk = disk;
|
||||
m_diskname = filename;
|
||||
}
|
||||
|
||||
void CatalogWidget::processNewlyLoadedDisk(QString diskfilename, DiskFile *disk)
|
||||
{
|
||||
if (m_disk == disk) {
|
||||
QUrl url = QUrl::fromLocalFile(diskfilename);
|
||||
QString shortfilename = url.fileName();
|
||||
QFontMetrics *fm = new QFontMetrics(ui->catalog_list->font());
|
||||
QRect maxrect;
|
||||
ui->volume_label->setText(shortfilename);
|
||||
foreach(FileDescriptiveEntry fde, m_disk->getAllFDEs()) {
|
||||
QString filetype = fde.fileType();
|
||||
QString filename = AppleString(fde.filename).printable().simplified();
|
||||
int size = fde.lengthInSectors;
|
||||
bool locked = fde.isLocked();
|
||||
QString sizeStr = QString("%1").arg(size,5,10,QChar(' ')).toUpper();
|
||||
QString text = QString("%1 %2 %3 %4").arg(locked?"*":" ").arg(sizeStr).arg(filetype).arg(filename);
|
||||
ui->catalog_list->addItem(new QListWidgetItem(text));
|
||||
QRect rect = fm->boundingRect(text);
|
||||
if (rect.width() > maxrect.width()) {
|
||||
maxrect = rect;
|
||||
}
|
||||
}
|
||||
ui->catalog_list->resize(maxrect.width(),ui->catalog_list->size().height());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void CatalogWidget::unloadDisk(DiskFile *disk)
|
||||
{
|
||||
if (m_disk == disk) {
|
||||
m_disk = 0;
|
||||
}
|
||||
ui->catalog_list->clear();
|
||||
ui->volume_label->clear();
|
||||
}
|
||||
|
||||
|
37
src/catalogwidget.h
Normal file
37
src/catalogwidget.h
Normal file
@ -0,0 +1,37 @@
|
||||
#ifndef CATALOGWIDGET_H
|
||||
#define CATALOGWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "diskfile.h"
|
||||
|
||||
namespace Ui {
|
||||
class CatalogWidget;
|
||||
}
|
||||
|
||||
class CatalogWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
public:
|
||||
explicit CatalogWidget(QWidget *parent = 0);
|
||||
~CatalogWidget();
|
||||
|
||||
public slots:
|
||||
void prepForNewDisk(QString filename, DiskFile *disk);
|
||||
void processNewlyLoadedDisk(QString filename, DiskFile *disk);
|
||||
void unloadDisk(DiskFile *disk);
|
||||
|
||||
signals:
|
||||
void newFileSelected(FileDescriptiveEntry *entry);
|
||||
|
||||
private:
|
||||
|
||||
Ui::CatalogWidget *ui;
|
||||
|
||||
DiskFile *m_disk;
|
||||
QString m_diskname;
|
||||
};
|
||||
|
||||
#endif // CATALOGWIDGET_H
|
42
src/catalogwidget.ui
Normal file
42
src/catalogwidget.ui
Normal file
@ -0,0 +1,42 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>CatalogWidget</class>
|
||||
<widget class="QWidget" name="CatalogWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>328</width>
|
||||
<height>560</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="volume_label">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListWidget" name="catalog_list"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="file_label">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
7
src/disassembler.cxx
Normal file
7
src/disassembler.cxx
Normal file
@ -0,0 +1,7 @@
|
||||
#include "disassembler.h"
|
||||
|
||||
|
||||
QStringList Disassembler::disassemble(quint16 address, QByteArray values)
|
||||
{
|
||||
return QStringList() << "TODO";
|
||||
}
|
13
src/disassembler.h
Normal file
13
src/disassembler.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef DISASSEMBLER_H
|
||||
#define DISASSEMBLER_H
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QStringList>
|
||||
|
||||
class Disassembler
|
||||
{
|
||||
public:
|
||||
static QStringList disassemble(quint16 address, QByteArray values);
|
||||
};
|
||||
|
||||
#endif // DISASSEMBLER_H
|
109
src/diskfile.cxx
Normal file
109
src/diskfile.cxx
Normal file
@ -0,0 +1,109 @@
|
||||
#include "diskfile.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QDataStream>
|
||||
#include <QDebug>
|
||||
|
||||
#include "tracksectorlist.h"
|
||||
|
||||
DiskFile::DiskFile(QString filename)
|
||||
{
|
||||
if (!filename.isEmpty())
|
||||
{
|
||||
read(filename);
|
||||
}
|
||||
}
|
||||
|
||||
bool DiskFile::read(QString filename)
|
||||
{
|
||||
QFile infile(filename);
|
||||
if (infile.open(QIODevice::ReadOnly))
|
||||
{
|
||||
QDataStream qds(&infile);
|
||||
for (int track = 0; track < 35; track++)
|
||||
{
|
||||
for (int sector = 0; sector < 16; sector++)
|
||||
{
|
||||
char buffer[256];
|
||||
if (qds.readRawData(buffer,256) == 256)
|
||||
{
|
||||
Sector sec;
|
||||
sec.setTrackSector(track,sector);
|
||||
sec.setData(QByteArray(buffer,256));
|
||||
m_contents[track][sector] = sec;
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Invalid sector read!";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
qDebug() << "Could not open file " << filename;
|
||||
return false;
|
||||
}
|
||||
|
||||
VTOC DiskFile::getVTOC()
|
||||
{
|
||||
return getSector(17,0).promoteToVTOC();
|
||||
}
|
||||
|
||||
QList<CatalogSector> DiskFile::getCatalogSectors()
|
||||
{
|
||||
QList<CatalogSector> retval;
|
||||
VTOC vtoc = getVTOC();
|
||||
TSPair ts = vtoc.firstCatalogSector();
|
||||
|
||||
CatalogSector cs = getSector(ts).promoteToCatalogSector();
|
||||
retval.append(cs);
|
||||
while (cs.nextCatalogSector() != TSPair(0,0)) {
|
||||
ts = cs.nextCatalogSector();
|
||||
cs = getSector(ts).promoteToCatalogSector();
|
||||
retval.append(cs);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
QByteArray DiskFile::getFile(FileDescriptiveEntry fde)
|
||||
{
|
||||
QByteArray retval;
|
||||
TrackSectorList tsl = getSector(fde.firstTSListSector).promoteToTrackSectorList();
|
||||
return getDataFromTrackSectorList(tsl);
|
||||
}
|
||||
|
||||
|
||||
QByteArray DiskFile::getDataFromTrackSectorList(TrackSectorList tsl)
|
||||
{
|
||||
QByteArray retval;
|
||||
|
||||
foreach(TSPair pair, tsl.getDataTSPairs())
|
||||
{
|
||||
Sector sec = getSector(pair);
|
||||
retval.append(sec.rawData());
|
||||
}
|
||||
|
||||
if (tsl.getNextTSList() != TSPair(0,0)) {
|
||||
TrackSectorList nextTsl = getSector(tsl.getNextTSList()).promoteToTrackSectorList();
|
||||
retval.append(getDataFromTrackSectorList(nextTsl));
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
QList<FileDescriptiveEntry> DiskFile::getAllFDEs() {
|
||||
QList<FileDescriptiveEntry> retval;
|
||||
|
||||
QList<CatalogSector> sectors = getCatalogSectors();
|
||||
|
||||
foreach (CatalogSector cs, sectors)
|
||||
{
|
||||
QList<FileDescriptiveEntry> fdes = cs.getFDEs();
|
||||
retval.append(fdes);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
45
src/diskfile.h
Normal file
45
src/diskfile.h
Normal file
@ -0,0 +1,45 @@
|
||||
#ifndef DISKFILE_H
|
||||
#define DISKFILE_H
|
||||
|
||||
#include <Qt>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
|
||||
#include "util.h"
|
||||
#include "sector.h"
|
||||
#include "vtoc.h"
|
||||
|
||||
|
||||
|
||||
class DiskFile
|
||||
{
|
||||
public:
|
||||
DiskFile(QString filename = "");
|
||||
|
||||
bool read(QString filename);
|
||||
|
||||
Sector &getSector(TSPair ts) { return getSector(ts.track, ts.sector); }
|
||||
|
||||
Sector &getSector(int track, int sector) {
|
||||
return m_contents[track][sector];
|
||||
}
|
||||
|
||||
VTOC getVTOC();
|
||||
|
||||
QList<CatalogSector> getCatalogSectors();
|
||||
|
||||
QByteArray getFile(FileDescriptiveEntry fde);
|
||||
|
||||
QByteArray getDataFromTrackSectorList(TrackSectorList tsl);
|
||||
|
||||
QList<FileDescriptiveEntry> getAllFDEs();
|
||||
|
||||
|
||||
private:
|
||||
|
||||
QMap< int, QMap< int, Sector> > m_contents;
|
||||
|
||||
};
|
||||
|
||||
#endif // DISKFILE_H
|
2
src/filedescriptiveentry.cxx
Normal file
2
src/filedescriptiveentry.cxx
Normal file
@ -0,0 +1,2 @@
|
||||
#include "filedescriptiveentry.h"
|
||||
|
44
src/filedescriptiveentry.h
Normal file
44
src/filedescriptiveentry.h
Normal file
@ -0,0 +1,44 @@
|
||||
#ifndef FILEDESCRIPTIVEENTRY_H
|
||||
#define FILEDESCRIPTIVEENTRY_H
|
||||
|
||||
#include "util.h"
|
||||
#include <QDebug>
|
||||
#include "applestring.h"
|
||||
|
||||
struct FileDescriptiveEntry {
|
||||
TSPair firstTSListSector;
|
||||
int fileTypeAndFlags;
|
||||
AppleString filename;
|
||||
quint16 lengthInSectors;
|
||||
|
||||
QString fileType() {
|
||||
if (fileTypeAndFlags & IntegerBasicFile) { return "I"; }
|
||||
if (fileTypeAndFlags & ApplesoftBasicFile) { return "A"; }
|
||||
if (fileTypeAndFlags & RelocatableFile) { return "R"; }
|
||||
if (fileTypeAndFlags & RawBinaryFile) { return "B"; }
|
||||
if (fileTypeAndFlags & TypeSFile) { return "S"; }
|
||||
if (fileTypeAndFlags & TypeAFile) { return "a"; }
|
||||
if (fileTypeAndFlags & TypeBFile) { return "b"; }
|
||||
return "T";
|
||||
}
|
||||
|
||||
bool isLocked() { return (fileTypeAndFlags & IsLocked); }
|
||||
|
||||
void dump() {
|
||||
qDebug() << "First TS List Sector: Track: " << QString("%1").arg(firstTSListSector.track,2,16,QChar('0')).toUpper()
|
||||
<< " Sector: " << QString("%1").arg(firstTSListSector.sector,2,16,QChar('0')).toUpper();
|
||||
qDebug() << "File Type and Flags: " << QString::number((quint8)fileTypeAndFlags) << "(" << fileType() << "," << (isLocked()?"Locked":"Unlocked") << ")";
|
||||
qDebug() << "Filename: " << filename.printable();
|
||||
qDebug() << "Length in Sectors: " << lengthInSectors;
|
||||
}
|
||||
|
||||
void catalog() {
|
||||
QString output = QString("%1 %2 %3 %4").arg(QString(isLocked()?"*":" "))
|
||||
.arg(lengthInSectors,3,10,QChar('0'))
|
||||
.arg(fileType())
|
||||
.arg(filename.printable().trimmed());
|
||||
qDebug() << output;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // FILEDESCRIPTIVEENTRY_H
|
13
src/genericfile.cxx
Normal file
13
src/genericfile.cxx
Normal file
@ -0,0 +1,13 @@
|
||||
#include "genericfile.h"
|
||||
|
||||
GenericFile::GenericFile(QByteArray data)
|
||||
{
|
||||
if (!data.isEmpty()) {
|
||||
setData(data);
|
||||
}
|
||||
}
|
||||
|
||||
void GenericFile::setData(QByteArray data)
|
||||
{
|
||||
m_data = data;
|
||||
}
|
16
src/genericfile.h
Normal file
16
src/genericfile.h
Normal file
@ -0,0 +1,16 @@
|
||||
#ifndef GENERICFILE_H
|
||||
#define GENERICFILE_H
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
class GenericFile
|
||||
{
|
||||
public:
|
||||
GenericFile(QByteArray data = QByteArray());
|
||||
virtual void setData(QByteArray data);
|
||||
|
||||
protected:
|
||||
QByteArray m_data;
|
||||
};
|
||||
|
||||
#endif // GENERICFILE_H
|
48
src/main.cpp
Normal file
48
src/main.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
#include <QApplication>
|
||||
|
||||
#include "mainwindow.h"
|
||||
#include "binaryfile.h"
|
||||
#include "genericfile.h"
|
||||
#include "diskfile.h"
|
||||
#include "catalogsector.h"
|
||||
#include "applesoftfile.h"
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
/*
|
||||
// DiskFile df("/home/mlong/Desktop/dos.3.3.system.master.dsk");
|
||||
DiskFile df("/home/mlong/Desktop/missing_ring_good.dsk");
|
||||
|
||||
df.getVTOC().dump();
|
||||
|
||||
QList<CatalogSector> sectors = df.getCatalogSectors();
|
||||
|
||||
FileDescriptiveEntry toLoad;
|
||||
|
||||
foreach (FileDescriptiveEntry fde, df.getAllFDEs()) {
|
||||
fde.catalog();
|
||||
if (fde.filename.printable().contains("ASM.DATA")) {
|
||||
toLoad = fde;
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray file = df.getFile(toLoad);
|
||||
|
||||
BinaryFile myfile;
|
||||
myfile.setData(file);
|
||||
myfile.dump();
|
||||
|
||||
|
||||
//ApplesoftFile af(file);
|
||||
//af.list();
|
||||
*/
|
||||
|
||||
QApplication a(argc, argv);
|
||||
MainWindow w;
|
||||
w.loadDiskFile("/home/mlong/Desktop/missing_ring_good.dsk");
|
||||
w.show();
|
||||
|
||||
return a.exec();
|
||||
|
||||
}
|
||||
|
63
src/mainwindow.cxx
Normal file
63
src/mainwindow.cxx
Normal file
@ -0,0 +1,63 @@
|
||||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
m_disk = 0;
|
||||
|
||||
connect(ui->action_Quit, SIGNAL(triggered()), qApp, SLOT(quit()));
|
||||
connect(ui->action_Load_Disk_Image, SIGNAL(triggered()), SLOT(showLoadDialog()));
|
||||
|
||||
connect(this, SIGNAL(diskFileLoading(QString, DiskFile*)),
|
||||
ui->catalogWidget, SLOT(prepForNewDisk(QString,DiskFile*)));
|
||||
connect(this, SIGNAL(diskFileLoaded(QString,DiskFile*)),
|
||||
ui->catalogWidget, SLOT(processNewlyLoadedDisk(QString,DiskFile*)));
|
||||
connect(this, SIGNAL(diskFileUnloading(DiskFile*)),
|
||||
ui->catalogWidget, SLOT(unloadDisk(DiskFile*)));
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void MainWindow::loadDiskFile(QString filename)
|
||||
{
|
||||
if (m_disk) {
|
||||
unloadDiskFile();
|
||||
}
|
||||
|
||||
m_disk = new DiskFile();
|
||||
emit diskFileLoading(filename,m_disk);
|
||||
if (m_disk->read(filename)) {
|
||||
emit diskFileLoaded(filename,m_disk);
|
||||
} else {
|
||||
emit diskFileLoadFailed(filename,m_disk);
|
||||
delete m_disk;
|
||||
m_disk = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::unloadDiskFile()
|
||||
{
|
||||
emit diskFileUnloading(m_disk);
|
||||
delete m_disk;
|
||||
m_disk = 0;
|
||||
emit diskFileUnloaded();
|
||||
}
|
||||
|
||||
void MainWindow::showLoadDialog()
|
||||
{
|
||||
QString filename = QFileDialog::getOpenFileName(this,
|
||||
tr("Open Disk Image"),
|
||||
"/home/mlong/Desktop",
|
||||
"Disk Images (*.do *.dsk)");
|
||||
if (!filename.isEmpty()) {
|
||||
loadDiskFile(filename);
|
||||
}
|
||||
}
|
39
src/mainwindow.h
Normal file
39
src/mainwindow.h
Normal file
@ -0,0 +1,39 @@
|
||||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
#include "diskfile.h"
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = 0);
|
||||
~MainWindow();
|
||||
|
||||
public slots:
|
||||
void loadDiskFile(QString filename);
|
||||
void unloadDiskFile();
|
||||
|
||||
void showLoadDialog();
|
||||
|
||||
signals:
|
||||
void diskFileLoading(QString filename, DiskFile *file);
|
||||
void diskFileLoaded(QString filename, DiskFile *file);
|
||||
void diskFileLoadFailed(QString filename, DiskFile *file);
|
||||
void diskFileUnloading(DiskFile *file);
|
||||
void diskFileUnloaded();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
|
||||
DiskFile *m_disk;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
116
src/mainwindow.ui
Normal file
116
src/mainwindow.ui
Normal file
@ -0,0 +1,116 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>AppleSAWS</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="childrenCollapsible">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<widget class="CatalogWidget" name="catalogWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>2</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>400</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="baseSize">
|
||||
<size>
|
||||
<width>300</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QMdiArea" name="mdiArea">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Expanding">
|
||||
<horstretch>3</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>20</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menu_File">
|
||||
<property name="title">
|
||||
<string>&File</string>
|
||||
</property>
|
||||
<addaction name="action_Load_Disk_Image"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_Quit"/>
|
||||
</widget>
|
||||
<addaction name="menu_File"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
<widget class="QToolBar" name="toolBar">
|
||||
<property name="windowTitle">
|
||||
<string>toolBar</string>
|
||||
</property>
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
<action name="action_Load_Disk_Image">
|
||||
<property name="text">
|
||||
<string>&Load Disk Image</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_Quit">
|
||||
<property name="text">
|
||||
<string>&Quit</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CatalogWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>catalogwidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
47
src/sector.cxx
Normal file
47
src/sector.cxx
Normal file
@ -0,0 +1,47 @@
|
||||
#include "sector.h"
|
||||
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
|
||||
QByteRef Sector::operator[](uint offset) {
|
||||
if (offset > 255) {
|
||||
offset = 255;
|
||||
}
|
||||
return m_data[offset];
|
||||
}
|
||||
|
||||
bool Sector::setData(QByteArray data) {
|
||||
if (data.length() != 256) return false;
|
||||
|
||||
m_data = data;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sector::dump() {
|
||||
qDebug() << "Dumping Track " << track() << "Sector " << sector() << " ...";
|
||||
for (int jdx = 0; jdx < 16; jdx++)
|
||||
{
|
||||
QString line;
|
||||
line += QString("%1 (%2): ").arg(jdx*16,2,16,QChar('0')).arg(jdx*16,3,10,QChar(' '));
|
||||
for (int idx = 0; idx < 16; idx++)
|
||||
{
|
||||
int offset = (jdx*16) + idx;
|
||||
quint8 val = m_data[offset];
|
||||
line += QString("%1 ").arg(val,2,16,QChar('0'));
|
||||
if (idx == 7) line += " ";
|
||||
}
|
||||
line = line.toUpper();
|
||||
line += " ";
|
||||
for (int idx = 0; idx < 16; idx++)
|
||||
{
|
||||
int offset = (jdx*16) + idx;
|
||||
quint8 val = m_data[offset];
|
||||
if (val > 127) { val -= 128; }
|
||||
QChar ch(val);
|
||||
line += QString("%1").arg(ch.isPrint()?ch:'.');
|
||||
}
|
||||
|
||||
qDebug() << line;
|
||||
}
|
||||
}
|
||||
|
57
src/sector.h
Normal file
57
src/sector.h
Normal file
@ -0,0 +1,57 @@
|
||||
#ifndef SECTOR_H
|
||||
#define SECTOR_H
|
||||
|
||||
#include <QByteArray>
|
||||
|
||||
#include "vtoc.h"
|
||||
#include "catalogsector.h"
|
||||
#include "tracksectorlist.h"
|
||||
|
||||
class Sector
|
||||
{
|
||||
public:
|
||||
|
||||
Sector() {
|
||||
m_data.resize(256);
|
||||
m_track = 255;
|
||||
m_sector = 255;
|
||||
}
|
||||
|
||||
VTOC promoteToVTOC() {
|
||||
return VTOC(this);
|
||||
}
|
||||
|
||||
CatalogSector promoteToCatalogSector() {
|
||||
return CatalogSector(this);
|
||||
}
|
||||
|
||||
TrackSectorList promoteToTrackSectorList() {
|
||||
return TrackSectorList(this);
|
||||
}
|
||||
|
||||
int sector() { return m_sector; }
|
||||
int track() { return m_track; }
|
||||
|
||||
void setTrackSector(int track, int sector) {
|
||||
setTrack(track);
|
||||
setSector(sector);
|
||||
}
|
||||
|
||||
void setTrack(int track) { m_track = track; }
|
||||
void setSector(int sector) { m_sector = sector; }
|
||||
|
||||
QByteRef operator[](uint offset);
|
||||
|
||||
bool setData(QByteArray data);
|
||||
|
||||
void dump();
|
||||
|
||||
QByteArray rawData() { return m_data; }
|
||||
|
||||
private:
|
||||
QByteArray m_data;
|
||||
int m_track;
|
||||
int m_sector;
|
||||
};
|
||||
|
||||
#endif // SECTOR_H
|
24
src/tracksectorlist.cxx
Normal file
24
src/tracksectorlist.cxx
Normal file
@ -0,0 +1,24 @@
|
||||
#include "tracksectorlist.h"
|
||||
|
||||
#include "sector.h"
|
||||
|
||||
TrackSectorList::TrackSectorList(Sector *data)
|
||||
{
|
||||
m_data = data;
|
||||
|
||||
m_next_tslist.track = m_data->rawData()[0x01];
|
||||
m_next_tslist.sector = m_data->rawData()[0x02];
|
||||
|
||||
m_sector_offset.track = m_data->rawData()[0x05];
|
||||
m_sector_offset.sector = m_data->rawData()[0x06];
|
||||
|
||||
for (int idx = 0x0C; idx < 0xff; idx+=2)
|
||||
{
|
||||
TSPair ts(m_data->rawData()[idx],m_data->rawData()[idx+1]);
|
||||
if (ts == TSPair(0,0)) {
|
||||
break;
|
||||
} else {
|
||||
m_ts_pairs_for_data.append(ts);
|
||||
}
|
||||
}
|
||||
}
|
27
src/tracksectorlist.h
Normal file
27
src/tracksectorlist.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef TRACKSECTORLIST_H
|
||||
#define TRACKSECTORLIST_H
|
||||
|
||||
#include "util.h"
|
||||
|
||||
class Sector;
|
||||
|
||||
class TrackSectorList
|
||||
{
|
||||
public:
|
||||
TrackSectorList(Sector *data);
|
||||
|
||||
TSPair getNextTSList() const { return m_next_tslist; }
|
||||
TSPair getSectorOffset() const { return m_sector_offset; }
|
||||
|
||||
QList<TSPair> getDataTSPairs() { return m_ts_pairs_for_data; }
|
||||
|
||||
private:
|
||||
|
||||
TSPair m_next_tslist;
|
||||
TSPair m_sector_offset;
|
||||
QList<TSPair> m_ts_pairs_for_data;
|
||||
|
||||
Sector *m_data;
|
||||
};
|
||||
|
||||
#endif // TRACKSECTORLIST_H
|
58
src/util.h
Normal file
58
src/util.h
Normal file
@ -0,0 +1,58 @@
|
||||
#ifndef UTIL_H
|
||||
#define UTIL_H
|
||||
|
||||
#include <QPair>
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
|
||||
typedef enum {
|
||||
TextFile = 0x00,
|
||||
IntegerBasicFile = 0x01,
|
||||
ApplesoftBasicFile = 0x02,
|
||||
RawBinaryFile = 0x04,
|
||||
TypeSFile = 0x08,
|
||||
RelocatableFile = 0x10,
|
||||
TypeAFile = 0x20,
|
||||
TypeBFile= 0x40,
|
||||
IsLocked = 0x80
|
||||
} FileTypeFlag;
|
||||
|
||||
typedef enum {
|
||||
Inverse = 0x00, // 0x00 -- 0x3F
|
||||
Flash = 0x01, // 0x40 -- 0x7F
|
||||
Normal = 0x02, // 0x80 -- 0xBF
|
||||
NormalHigh = 0x04 // 0xC0 -- 0xFF
|
||||
} TextAttribute;
|
||||
|
||||
typedef enum {
|
||||
SetInvUC = 0x00,
|
||||
SetInvSp = 0x20,
|
||||
SetFlUC = 0x40,
|
||||
SetFlSp = 0x60,
|
||||
SetNormUC = 0x80,
|
||||
SetNormSp = 0xA0,
|
||||
SetNormAltUC = 0xC0,
|
||||
SetNormLC = 0xE0
|
||||
} TextSet;
|
||||
|
||||
struct TSPair {
|
||||
TSPair() { track = sector = 0; }
|
||||
TSPair(quint8 trackval, quint8 secval) { track=trackval; sector = secval; }
|
||||
quint8 track;
|
||||
quint8 sector;
|
||||
|
||||
bool operator==(const TSPair &other) {
|
||||
if (other.track == track && other.sector == sector) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator!=(const TSPair &other) {
|
||||
return !(operator==(other));
|
||||
}
|
||||
|
||||
void dump() { qDebug() << "TSPair: track: " << track << " sector: " << sector; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // UTIL_H
|
96
src/vtoc.cxx
Normal file
96
src/vtoc.cxx
Normal file
@ -0,0 +1,96 @@
|
||||
#include "vtoc.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QString>
|
||||
|
||||
#include "sector.h"
|
||||
|
||||
VTOC::VTOC(Sector *data)
|
||||
{
|
||||
m_data = data;
|
||||
}
|
||||
|
||||
TSPair VTOC::firstCatalogSector() {
|
||||
return TSPair(m_data->rawData()[0x01], m_data->rawData()[0x02]);
|
||||
}
|
||||
|
||||
quint8 VTOC::dosVersion() {
|
||||
return m_data->rawData()[0x03];
|
||||
}
|
||||
|
||||
quint8 VTOC::volumeNumber() {
|
||||
return m_data->rawData()[0x06];
|
||||
}
|
||||
|
||||
quint8 VTOC::maxTSPairs() {
|
||||
return m_data->rawData()[0x27];
|
||||
}
|
||||
|
||||
quint8 VTOC::lastTrackAllocated() {
|
||||
return m_data->rawData()[0x30];
|
||||
}
|
||||
|
||||
qint8 VTOC::directionOfAllocation() {
|
||||
return m_data->rawData()[0x31];
|
||||
}
|
||||
|
||||
quint8 VTOC::tracksPerDisk() {
|
||||
return m_data->rawData()[0x34];
|
||||
}
|
||||
|
||||
quint8 VTOC::sectorsPerDisk() {
|
||||
return m_data->rawData()[0x35];
|
||||
}
|
||||
|
||||
qint16 VTOC::bytesPerSector() {
|
||||
return m_data->rawData()[0x36] + (256 * m_data->rawData()[0x37]);
|
||||
}
|
||||
|
||||
bool VTOC::isSectorInUse(TSPair ts) {
|
||||
quint8 track = ts.track;
|
||||
quint8 sec = ts.sector;
|
||||
quint8 baseaddr = (track * 4) + 0x38;
|
||||
|
||||
quint16 word = (((quint16) m_data->rawData()[baseaddr]) *256) + (quint8) m_data->rawData()[baseaddr+1];
|
||||
quint16 bitpos = (quint16) 0x01 << (quint16) sec;
|
||||
|
||||
return !(word & bitpos);
|
||||
}
|
||||
|
||||
void VTOC::dump()
|
||||
{
|
||||
/*
|
||||
for (qint8 idx = 0x0f; idx >= 0; idx--) {
|
||||
quint8 shift;
|
||||
if (idx < 0x08) { shift = idx; } else { shift = idx-0x08; }
|
||||
qDebug() << "Idx: " << idx << "Shift: " << (quint8) shift << "Bitpos: " << (quint8) (0x01 << shift);
|
||||
}
|
||||
*/
|
||||
qDebug() << "Dumping VTOC Track " << m_data->track() << "Sector " << m_data->sector() << " ...";
|
||||
qDebug() << " Track number of first catalog sector: " << QString::number(firstCatalogSector().track);
|
||||
qDebug() << " Sector number of first catalog sector: " << QString::number(firstCatalogSector().sector);
|
||||
qDebug() << " Release number of DOS used to INIT disk: " << QString::number(dosVersion());
|
||||
qDebug() << " Disk Volume Number: " << QString::number(volumeNumber());
|
||||
qDebug() << " Max track/sector pairs that fit in t/s list sector (122=256): " << QString::number(maxTSPairs());
|
||||
qDebug() << " Last track where sectors were allocated: " << QString::number(lastTrackAllocated());
|
||||
qDebug() << " Direction of track allocations (+/- 1): " << QString::number(directionOfAllocation());
|
||||
qDebug() << " Number tracks per disk: " << QString::number(tracksPerDisk());
|
||||
qDebug() << " Number sectors per disk: " << QString::number(sectorsPerDisk());
|
||||
qDebug() << " Number bytes/sector: " << QString::number(bytesPerSector());
|
||||
qDebug() << " Track Usage (.=free, 0-F=used):";
|
||||
for (quint8 track = 0; track < m_data->rawData()[0x34];track++)
|
||||
{
|
||||
qDebug() << " " << QString("Track %1:").arg((int) track,2,10,QChar('0')) << buildUseString(track);
|
||||
}
|
||||
}
|
||||
|
||||
QString VTOC::buildUseString(quint8 track) {
|
||||
QString usestr;
|
||||
for (qint8 sec = 0x0f; sec >= 0; sec--)
|
||||
{
|
||||
usestr.append(isSectorInUse(TSPair(track,sec))?QString::number(sec,16).toUpper():"-");
|
||||
}
|
||||
return usestr;
|
||||
}
|
||||
|
||||
|
33
src/vtoc.h
Normal file
33
src/vtoc.h
Normal file
@ -0,0 +1,33 @@
|
||||
#ifndef VTOC_H
|
||||
#define VTOC_H
|
||||
|
||||
#include <Qt>
|
||||
#include "util.h"
|
||||
class Sector;
|
||||
class QString;
|
||||
|
||||
|
||||
class VTOC
|
||||
{
|
||||
public:
|
||||
VTOC(Sector *data);
|
||||
|
||||
void dump();
|
||||
TSPair firstCatalogSector();
|
||||
quint8 dosVersion();
|
||||
quint8 volumeNumber();
|
||||
quint8 maxTSPairs();
|
||||
quint8 lastTrackAllocated();
|
||||
qint8 directionOfAllocation();
|
||||
quint8 tracksPerDisk();
|
||||
quint8 sectorsPerDisk();
|
||||
qint16 bytesPerSector();
|
||||
bool isSectorInUse(TSPair ts);
|
||||
|
||||
private:
|
||||
QString buildUseString(quint8 track);
|
||||
|
||||
Sector *m_data;
|
||||
};
|
||||
|
||||
#endif // VTOC_H
|
Loading…
Reference in New Issue
Block a user