git-svn-id: https://profuse.googlecode.com/svn/branches/v2@94 aa027e90-d47c-11dd-86d7-074df07e0730
This commit is contained in:
parent
ebb502b1f5
commit
8090387723
|
@ -18,6 +18,14 @@ BlockDevice::~BlockDevice()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BlockDevice::zeroBlock(unsigned block)
|
||||||
|
{
|
||||||
|
uint8_t bp[512];
|
||||||
|
std::memset(bp, 0, 512);
|
||||||
|
|
||||||
|
write(block, bp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark DiskImage
|
#pragma mark DiskImage
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,8 @@ public:
|
||||||
|
|
||||||
virtual bool readOnly() = 0;
|
virtual bool readOnly() = 0;
|
||||||
virtual void sync() = 0;
|
virtual void sync() = 0;
|
||||||
|
|
||||||
|
void zeroBlock(unsigned block);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
2
Buffer.h
2
Buffer.h
|
@ -12,7 +12,9 @@ public:
|
||||||
|
|
||||||
void *buffer() const { return (void *)&_buffer[0]; }
|
void *buffer() const { return (void *)&_buffer[0]; }
|
||||||
unsigned size() const { return _buffer.size(); }
|
unsigned size() const { return _buffer.size(); }
|
||||||
|
|
||||||
void resize(unsigned size) { _buffer.resize(size); }
|
void resize(unsigned size) { _buffer.resize(size); }
|
||||||
|
void clear() { _buffer.clear(); }
|
||||||
|
|
||||||
void push8(uint8_t x) { _buffer.push_back(x); }
|
void push8(uint8_t x) { _buffer.push_back(x); }
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,144 @@
|
||||||
|
#include "DateTime.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <ctime>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
namespace ProDOS {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* date is a 16 bit value:
|
||||||
|
*
|
||||||
|
* 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
||||||
|
* +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
|
||||||
|
* | Year | Month | Day |
|
||||||
|
* +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
|
||||||
|
*
|
||||||
|
* time is a 16 bit value:
|
||||||
|
*
|
||||||
|
* 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
|
||||||
|
* +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
|
||||||
|
* |0 0 0| Hour | |0 0| Minute |
|
||||||
|
* +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ProDOS technote 28
|
||||||
|
*
|
||||||
|
* The following definition allows the same range of years that the Apple IIgs
|
||||||
|
* Control Panel CDA currently does:
|
||||||
|
*
|
||||||
|
* o A seven-bit ProDOS year value is in the range 0 to 99
|
||||||
|
* (100 through 127 are invalid)
|
||||||
|
* o Year values from 40 to 99 represent 1940 through 1999
|
||||||
|
* o Year values from 0 to 39 represent 2000 through 2039
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
DateTime::DateTime() :
|
||||||
|
_yymmdd(0), _hhmm(0)
|
||||||
|
{
|
||||||
|
init(std::time(NULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime::DateTime(uint32_t dtm) :
|
||||||
|
_yymmdd((dtm >> 16) & 0xff), _hhmm(dtm & 0xff)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime::DateTime(unsigned yymmdd, unsigned hhmm) :
|
||||||
|
_yymmdd(yymmdd), _hhmm(hhmm)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
DateTime::DateTime(std::time_t time) :
|
||||||
|
_yymmdd(0), _hhmm(0)
|
||||||
|
{
|
||||||
|
init(time);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DateTime::DateTime(unsigned year, unsigned month, unsigned day,
|
||||||
|
unsigned hour, unsigned minute) :
|
||||||
|
_yymmdd(0), _hhmm(0)
|
||||||
|
{
|
||||||
|
init(year, month, day, hour, minute);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTime::init(std::time_t time)
|
||||||
|
{
|
||||||
|
tm t;
|
||||||
|
::localtime_r(&time, &t);
|
||||||
|
init(t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DateTime::init(unsigned year, unsigned month, unsigned day, unsigned hour, unsigned minute)
|
||||||
|
{
|
||||||
|
|
||||||
|
//printf("%d %d %d %d %d\n", year, month, day, hour, minute);
|
||||||
|
|
||||||
|
// 1940 is the earliest year, so clamp to 1940-01-01 00:00
|
||||||
|
if (year < 1940)
|
||||||
|
{
|
||||||
|
_yymmdd = (40 << 9) | (1 << 5) | 1;
|
||||||
|
_hhmm = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// 2039 is the latest year, so clamp to 2039-12-31 23:59
|
||||||
|
if (year > 2039)
|
||||||
|
{
|
||||||
|
_yymmdd = (39 << 9) | (12 << 5) | 31;
|
||||||
|
_hhmm = (23 << 8) | 59;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (year >= 2000) year -= 2000;
|
||||||
|
else year -= 1900;
|
||||||
|
|
||||||
|
_hhmm = minute | (hour << 8);
|
||||||
|
|
||||||
|
_yymmdd = day | (month << 5) | (year << 9);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned DateTime::year() const
|
||||||
|
{
|
||||||
|
unsigned tmp = _yymmdd >> 9;
|
||||||
|
//if (tmp > 100) return 0;
|
||||||
|
|
||||||
|
if (tmp <= 39) tmp += 100;
|
||||||
|
|
||||||
|
return tmp + 1900;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A positive or 0 value for tm_isdst causes mktime() to presume initially
|
||||||
|
* that Daylight Savings Time, respectively, is or is not in effect for
|
||||||
|
* the specified time. A negative value for tm_isdst causes mktime() to
|
||||||
|
* attempt to determine whether Daylight Saving Time is in effect for the
|
||||||
|
* specified time.
|
||||||
|
*/
|
||||||
|
|
||||||
|
std::time_t DateTime::toUnix() const
|
||||||
|
{
|
||||||
|
tm t;
|
||||||
|
|
||||||
|
if (_yymmdd == 0) return 0;
|
||||||
|
|
||||||
|
std::memset(&t, 0, sizeof(tm));
|
||||||
|
|
||||||
|
t.tm_min = minute();
|
||||||
|
t.tm_hour = hour();
|
||||||
|
t.tm_isdst = -1;
|
||||||
|
|
||||||
|
t.tm_mday = day();
|
||||||
|
t.tm_mon = month() - 1;
|
||||||
|
t.tm_year = year() - 1900;
|
||||||
|
|
||||||
|
return std::mktime(&t);
|
||||||
|
// convert back via locatime & fudge for dst?
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
|
@ -0,0 +1,96 @@
|
||||||
|
#ifndef __PRODOS_DATE_TIME__
|
||||||
|
#define __PRODOS_DATE_TIME__
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace ProDOS {
|
||||||
|
|
||||||
|
class DateTime
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DateTime();
|
||||||
|
DateTime(std::time_t);
|
||||||
|
DateTime(uint32_t);
|
||||||
|
DateTime(unsigned, unsigned);
|
||||||
|
|
||||||
|
DateTime(unsigned year, unsigned month, unsigned day,
|
||||||
|
unsigned hour, unsigned minute);
|
||||||
|
|
||||||
|
std::time_t toUnix() const;
|
||||||
|
|
||||||
|
|
||||||
|
operator std::time_t() const;
|
||||||
|
operator uint32_t() const;
|
||||||
|
|
||||||
|
unsigned date() const;
|
||||||
|
unsigned time() const;
|
||||||
|
|
||||||
|
unsigned minute() const;
|
||||||
|
unsigned hour() const;
|
||||||
|
unsigned day() const;
|
||||||
|
unsigned month() const;
|
||||||
|
unsigned year() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init(std::time_t);
|
||||||
|
void init(unsigned, unsigned, unsigned, unsigned, unsigned);
|
||||||
|
|
||||||
|
unsigned _yymmdd;
|
||||||
|
unsigned _hhmm;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline DateTime::operator std::time_t() const
|
||||||
|
{
|
||||||
|
return toUnix();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DateTime::operator uint32_t() const
|
||||||
|
{
|
||||||
|
return (_yymmdd << 16) | _hhmm;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned DateTime::date() const
|
||||||
|
{
|
||||||
|
return _yymmdd;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned DateTime::time() const
|
||||||
|
{
|
||||||
|
return _hhmm;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned DateTime::minute() const
|
||||||
|
{
|
||||||
|
return _hhmm & 0x3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned DateTime::hour() const
|
||||||
|
{
|
||||||
|
return (_hhmm >> 8) & 0x1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned DateTime::day() const
|
||||||
|
{
|
||||||
|
return _yymmdd & 0x1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline unsigned DateTime::month() const
|
||||||
|
{
|
||||||
|
return (_yymmdd >> 5) & 0x0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
inline unsigned DateTime::year() const
|
||||||
|
{
|
||||||
|
unsigned tmp = _yymmdd >> 9;
|
||||||
|
if (tmp <= 39) tmp += 100;
|
||||||
|
return tmp + 1900;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
425
Directory.cpp
425
Directory.cpp
|
@ -1,10 +1,16 @@
|
||||||
#include "Directory"
|
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "Directory"
|
||||||
|
#include "Buffer.h"
|
||||||
|
#include "Endian.h"
|
||||||
|
|
||||||
#include "Exception.h"
|
#include "Exception.h"
|
||||||
|
|
||||||
|
|
||||||
using namespace ProFUSE;
|
using namespace ProFUSE;
|
||||||
|
using namespace LittleEndian;
|
||||||
|
|
||||||
static bool isalpha(unsigned c)
|
static bool isalpha(unsigned c)
|
||||||
{
|
{
|
||||||
|
@ -21,29 +27,18 @@ static bool isalnumdot(unsigned c)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint16_t read16(uint8_t *data, unsigned offset)
|
static bool islower(unsigned c)
|
||||||
{
|
{
|
||||||
return data[offset + 0]
|
return c >= 'a' && c <= 'z';
|
||||||
| (data[offset + 1] << 8) ;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t read24(uint8_t *data, unsigned offset)
|
|
||||||
{
|
|
||||||
return data[offset + 0]
|
|
||||||
| (data[offset + 1] << 8)
|
|
||||||
| (data[offset + 2] << 16) ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static uint32_t read32(uint8_t *data, unsigned offset)
|
/*
|
||||||
{
|
* ProDOS names:
|
||||||
return data[offset + 0]
|
* 1-15 letters, digits, or '.'
|
||||||
| (data[offset + 1] << 8)
|
* first character must be a letter.
|
||||||
| (data[offset + 2] << 16) ;
|
*/
|
||||||
| (data[offset + 3] << 24) ;
|
unsigned Entry::ValidName(const char *name)
|
||||||
}
|
|
||||||
|
|
||||||
unsigned ValidName(const char *name)
|
|
||||||
{
|
{
|
||||||
unsigned length;
|
unsigned length;
|
||||||
|
|
||||||
|
@ -61,48 +56,148 @@ unsigned ValidName(const char *name)
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory::Directory(unsigned type, const char *name)
|
Entry::Entry(unsigned type, const char *name)
|
||||||
|
{
|
||||||
|
_storageType = type;
|
||||||
|
_address = 0;
|
||||||
|
_volume = NULL;
|
||||||
|
|
||||||
|
// everything else initialized in setName.
|
||||||
|
setName(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry::Entry(const void *bp)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "Entry::Entry"
|
||||||
|
|
||||||
|
uint8_t x;
|
||||||
|
uint16_t xcase = 0;
|
||||||
|
_address = 0;
|
||||||
|
_volume = NULL;
|
||||||
|
_caseFlag = 0;
|
||||||
|
std::memset(_name, 0, 16);
|
||||||
|
std::memset(_namei, 0, 16);
|
||||||
|
|
||||||
|
x = Read8(bp, 0x00);
|
||||||
|
_storageType = x >> 4;
|
||||||
|
_nameLength = x & 0x0f;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < _nameLength; ++i)
|
||||||
|
{
|
||||||
|
_name[i] = _namei[i] = Read8(bp, i + 1);
|
||||||
|
// check legality?
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (_storageType)
|
||||||
|
{
|
||||||
|
case SeedlingFile:
|
||||||
|
case SaplingFile:
|
||||||
|
case TreeFile:
|
||||||
|
case PascalFile:
|
||||||
|
case ExtendedFile:
|
||||||
|
case DirectoryFile:
|
||||||
|
xcase = Read16(bp, 0x1c);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case VolumeHeader:
|
||||||
|
xcase = Read16(bp, 0x16);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (xcase & 0x8000)
|
||||||
|
{
|
||||||
|
_caseFlag = xcase;
|
||||||
|
xcase <<= 1;
|
||||||
|
for (unsigned i = 0; i < _nameLength; ++i, xcase <<= 1)
|
||||||
|
{
|
||||||
|
if (xcase & 0x8000)
|
||||||
|
_name[i] = _name[i] | 0x20;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry::~Entry()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IIgs Technote #8:
|
||||||
|
*
|
||||||
|
* bit 15 set
|
||||||
|
* bit 14 + i set if name[i] is lowercase.
|
||||||
|
*/
|
||||||
|
void Entry::setName(const char *name)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "Entry::setName"
|
||||||
|
|
||||||
|
unsigned caseFlag = 0x8000;
|
||||||
|
unsigned length = ValidName(name);
|
||||||
|
if (!length) throw Exception("Invalid name.");
|
||||||
|
|
||||||
|
std::memset(_name, 0, 16);
|
||||||
|
std::memset(_namei, 0, 16);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < length; ++i)
|
||||||
|
{
|
||||||
|
char c = name[i];
|
||||||
|
_name[i] = c;
|
||||||
|
_namei[i] = c & ~0x20; // upper
|
||||||
|
if (islower(c))
|
||||||
|
{
|
||||||
|
caseFlag |= (0x4000 >> i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_length = length;
|
||||||
|
_caseFlag = caseFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Directory::Directory(unsigned type, const char *name) :
|
||||||
|
Entry(type, name)
|
||||||
{
|
{
|
||||||
#undef __METHOD__
|
#undef __METHOD__
|
||||||
#define __METHOD__ "Directory::Directory"
|
#define __METHOD__ "Directory::Directory"
|
||||||
|
|
||||||
_nameLength = ValidName(name);
|
|
||||||
|
|
||||||
if (!_length)
|
_access = 0xe3;
|
||||||
throw Exception(__METHOD__ ": Invalid name.");
|
|
||||||
|
|
||||||
_storageType = type;
|
|
||||||
std::strncpy(_name, name, 16);
|
|
||||||
|
|
||||||
_access = 0xc3;
|
|
||||||
_entryLength = 0x27;
|
_entryLength = 0x27;
|
||||||
_entriesPerBlock = 13;
|
_entriesPerBlock = 13;
|
||||||
_fileCount = 0;
|
_fileCount = 0;
|
||||||
|
_version = 5; // ProDOS FST uses 5, ProDOS uses 0.
|
||||||
_device = NULL;
|
_minVersion = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory::Directory(const void *bp) :
|
Directory::Directory(const void *bp) :
|
||||||
|
Entry(4 + (const uint8_t *)bp),
|
||||||
_creation(0, 0)
|
_creation(0, 0)
|
||||||
{
|
{
|
||||||
#undef __METHOD__
|
#undef __METHOD__
|
||||||
#define __METHOD__ "Directory::Directory"
|
#define __METHOD__ "Directory::Directory"
|
||||||
|
|
||||||
const uint8_t *data = (const uint8_t *)bp;
|
// input is a block pointer. To simplify,
|
||||||
|
// create a new pointer past the 4-byte linked list part.
|
||||||
|
void *dp = 4 + (const uint8_t *)bp;
|
||||||
|
|
||||||
_storageType = data[0x00] >> 4;
|
_creation = DateTime(Read16(dp, 0x18), Read16(dp, 0x1a));
|
||||||
_nameLength = data[0x00] & 0x0f;
|
|
||||||
std::memcpy(_name, data + 1, _nameLength);
|
|
||||||
_name[_nameLength] = 0;
|
|
||||||
_creation = DateTime(read16(data, 0x1c), read16(data, 0x1e));
|
|
||||||
|
|
||||||
_access = data[0x22];
|
_version = Read8(dp, 0x1c);
|
||||||
_entryLength = data[0x23];
|
_minVersion = Read8(dp, 0x1d);
|
||||||
_entriesPerBlock = data[0x24];
|
|
||||||
|
|
||||||
_fileCount = read16(data, 0x25);
|
_access = Read8(dp, 0x1e);
|
||||||
|
_entryLength = Read8(dp, 0x1f);
|
||||||
|
_entriesPerBlock = Read8(dp, 0x20);
|
||||||
|
|
||||||
// parse child file entries.
|
_fileCount = read16(dp, 0x21);
|
||||||
|
|
||||||
|
// parse child file entries ... requires ability to read other blocks.
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory::~Directory()
|
Directory::~Directory()
|
||||||
|
@ -114,20 +209,248 @@ Directory::setAccess(unsigned access)
|
||||||
#undef __METHOD__
|
#undef __METHOD__
|
||||||
#define __METHOD__ "Directory::setAccess"
|
#define __METHOD__ "Directory::setAccess"
|
||||||
|
|
||||||
if ((access & 0xe3) != access)
|
if ((access & 0xe7) != access)
|
||||||
throw Exception(__METHOD__ ": Illegal access.");
|
throw Exception(__METHOD__ ": Illegal access.");
|
||||||
_access = access;
|
_access = access;
|
||||||
|
|
||||||
// todo -- mark dirty? update block?
|
// todo -- mark dirty? update block?
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory::setName(const char *name)
|
|
||||||
{
|
|
||||||
unsigned length = ValidName(name);
|
|
||||||
if (!length)
|
|
||||||
throw Exception(__METHOD__ ": Invalid name.");
|
|
||||||
_nameLength = length;
|
|
||||||
std::strncpy(_name, name, 16);
|
|
||||||
|
|
||||||
// todo -- update or mark dirty.
|
#pragma mark VolumeDirectory
|
||||||
|
|
||||||
|
VolumeDirectory(const char *name, BlockDevice *device) :
|
||||||
|
Directory(VolumeHeader, name)
|
||||||
|
{
|
||||||
|
_totalBlocks = device->blocks();
|
||||||
|
_bitmapPointer = 6;
|
||||||
|
|
||||||
|
_entryBlocks.push_back(2);
|
||||||
|
_entryBlocks.push_back(3);
|
||||||
|
_entryBlocks.push_back(4)
|
||||||
|
_entryBlocks.push_back(5);
|
||||||
|
|
||||||
|
std::auto_ptr<Bitmap> bitmap(new Bitmap(_totalBlocks));
|
||||||
|
|
||||||
|
|
||||||
|
// 2 bootcode blocks
|
||||||
|
for (unsigned i = 0; i < 2; ++i)
|
||||||
|
{
|
||||||
|
bitmap->allocBlock(i);
|
||||||
|
device->zeroBlock(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
//4 volume header blocks.
|
||||||
|
for (unsigned i = 2; i < 6; ++i)
|
||||||
|
{
|
||||||
|
bitmap->allocBlock(i);
|
||||||
|
|
||||||
|
buffer.clear();
|
||||||
|
// prev block, next block
|
||||||
|
buffer.push16le(i == 2 ? 0 : i - 1);
|
||||||
|
buffer.push16le(i == 5 ? 0 : i + 1);
|
||||||
|
|
||||||
|
if (i == 2)
|
||||||
|
{
|
||||||
|
// create the volume header.
|
||||||
|
// all ivars must be set.
|
||||||
|
write(&out);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.rezize(512);
|
||||||
|
device->write(i, buffer.buffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO -- create/write the volume entry....
|
||||||
|
|
||||||
|
// allocate blocks for the bitmap itself
|
||||||
|
unsigned bb = bitmap->bitmapBlocks();
|
||||||
|
for (unsigned i = 0; i < bb; ++i)
|
||||||
|
bitmap->allocBlock(i);
|
||||||
|
|
||||||
|
// now write the bitmap...
|
||||||
|
const uint8_t *bm = (const uint8_t *)bitmap->bitmap();
|
||||||
|
for (unsigned i = 0; i < bb; ++i)
|
||||||
|
{
|
||||||
|
device->writeBlock(_bitmapPointer + i, 512 * i + bm);
|
||||||
|
}
|
||||||
|
|
||||||
|
setDevice(device);
|
||||||
|
_bitmap = bitmap.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VolumeDirectory::~VolumeDirectory()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void VolumeDirectory::write(Buffer *out)
|
||||||
|
{
|
||||||
|
out->push8((VolumeHeader << 4 ) | (nameLength());
|
||||||
|
out->pushBytes(namei(), 15);
|
||||||
|
|
||||||
|
// reserved. SOS uses 0x75 for the first byte [?]
|
||||||
|
out->push8(0);
|
||||||
|
out->push8(0);
|
||||||
|
|
||||||
|
// last mod
|
||||||
|
out->push16le(_modification.date());
|
||||||
|
out->push16le(_modification.time());
|
||||||
|
|
||||||
|
// filename case bits
|
||||||
|
out->push16le(caseFlag());
|
||||||
|
|
||||||
|
// creation
|
||||||
|
out->push16le(creation().date());
|
||||||
|
out->push16le(creation().time());
|
||||||
|
|
||||||
|
out->push8(version());
|
||||||
|
out->push8(minVersion());
|
||||||
|
|
||||||
|
|
||||||
|
out->push8(access());
|
||||||
|
out->push8(entryLength());
|
||||||
|
out->push8(entriesPerBlock());
|
||||||
|
out->push16le(fileCount());
|
||||||
|
|
||||||
|
out->push16le(_bitmapPointer());
|
||||||
|
out->push16le(_totalBlocks);
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark SubDirectory
|
||||||
|
|
||||||
|
SubDirectory::SubDirectory(unsigned type, const char *name) :
|
||||||
|
Directory(type, name)
|
||||||
|
{
|
||||||
|
_parentPointer = 0;
|
||||||
|
_parentEntryNumber = 0;
|
||||||
|
_parentEntryLength = 0x27;
|
||||||
|
}
|
||||||
|
|
||||||
|
SubDirectory::SubDirectory(const void *bp) :
|
||||||
|
Directory(bp)
|
||||||
|
{
|
||||||
|
const void *dp = 4 + (const uint8_t *)bp;
|
||||||
|
|
||||||
|
_parentPointer = Read16(dp, 0x23);
|
||||||
|
_parentEntryNumber = Read8(dp, 0x25);
|
||||||
|
_parentEntryLength = Read8(dp, 0x26);
|
||||||
|
}
|
||||||
|
|
||||||
|
SubDirectory::~SubDirectory
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void SubDirectory::write(Buffer *out)
|
||||||
|
{
|
||||||
|
out->push8((VolumeHeader << 4 ) | (nameLength());
|
||||||
|
out->pushBytes(namei(), 15);
|
||||||
|
|
||||||
|
// reserved. 0x76 is stored in the first byte.
|
||||||
|
// no one knows why.
|
||||||
|
out->push8(0x76);
|
||||||
|
out->push8(0);
|
||||||
|
out->push8(0);
|
||||||
|
out->push8(0);
|
||||||
|
out->push8(0);
|
||||||
|
out->push8(0);
|
||||||
|
out->push8(0);
|
||||||
|
out->push8(0);
|
||||||
|
|
||||||
|
// creation
|
||||||
|
out->push16le(creation().date());
|
||||||
|
out->push16le(creation().time());
|
||||||
|
|
||||||
|
out->push8(version());
|
||||||
|
out->push8(minVersion());
|
||||||
|
|
||||||
|
out->push8(access());
|
||||||
|
out->push8(entryLength());
|
||||||
|
out->push8(entriesPerBlock());
|
||||||
|
out->push16le(fileCount());
|
||||||
|
out->push16le(_parentPointer);
|
||||||
|
out->push8(_parentEntryNumber);
|
||||||
|
out->push8(_parentEntryLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
FileEntry::FileEntry(unsigned type, const char *name) :
|
||||||
|
Entry(type, name)
|
||||||
|
{
|
||||||
|
_fileType = type == DirectoryFile ? 0x0f : 0x00;
|
||||||
|
_keyPointer = 0;
|
||||||
|
_blocksUsed = 0;
|
||||||
|
_eof = 0;
|
||||||
|
_access = 0xe3;
|
||||||
|
_auxType = 0;
|
||||||
|
_headerPointer = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FileEntry::FileEntry(const void *vp) :
|
||||||
|
Entry(vp),
|
||||||
|
_creation(0,0),
|
||||||
|
_modification(0,0)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "FileEntry::FileEntry"
|
||||||
|
|
||||||
|
switch(storageType())
|
||||||
|
{
|
||||||
|
case SeedlingFile:
|
||||||
|
case SaplingFile:
|
||||||
|
case TreeFile:
|
||||||
|
case PascalFile:
|
||||||
|
case ExtendedFile:
|
||||||
|
case DirectoryFile:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw Exception(__METHOD__ ": Invalid storage type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_fileType = Read8(vp, 0x10);
|
||||||
|
_keyPointer = Read16(vp, 0x11);
|
||||||
|
_blocksUsed = Read16(vp, 0x13);
|
||||||
|
_eof = Read24(vp, 0x15);
|
||||||
|
_creation = DateTime(Read16(vp, 0x18), Read16(vp, 0x1a));
|
||||||
|
_access = Read8(vp, 0x1e);
|
||||||
|
_auxType = Read16(vp, 0x1f);
|
||||||
|
_modification = DateTime(Read16(vp, 0x21), Read16(vp, 0x23));
|
||||||
|
_headerPointer = Read16(vp, 0x25);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
FileEntry::~FileEntry()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FileEntry::write(Buffer *out)
|
||||||
|
{
|
||||||
|
out->push8((VolumeHeader << 4 ) | (nameLength());
|
||||||
|
out->pushBytes(namei(), 15);
|
||||||
|
|
||||||
|
out->push8(_fileType);
|
||||||
|
out->push16le(_keyPointer);
|
||||||
|
out->push16le(_blocksUsed);
|
||||||
|
out-push24le(_eof);
|
||||||
|
|
||||||
|
// creation
|
||||||
|
out->push16le(_creation.date());
|
||||||
|
out->push16le(_creation.time());
|
||||||
|
|
||||||
|
// case bits
|
||||||
|
out->push16le(caseFlag());
|
||||||
|
|
||||||
|
out->push8(_access);
|
||||||
|
put->push16le(_auxType);
|
||||||
|
|
||||||
|
// modification
|
||||||
|
out->push16le(_modification.date());
|
||||||
|
out->push16le(_modification.time());
|
||||||
|
|
||||||
|
out->push16le(_headerPointer);
|
||||||
|
}
|
53
Directory.h
53
Directory.h
|
@ -15,25 +15,44 @@ class FileEntry;
|
||||||
class Volume;
|
class Volume;
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum Access {
|
||||||
DestroyEnabled = 0x80,
|
DestroyEnabled = 0x80,
|
||||||
RenameEnabled = 0x40,
|
RenameEnabled = 0x40,
|
||||||
BackupNeeded = 0x20,
|
BackupNeeded = 0x20,
|
||||||
|
Invisible = 0x04,
|
||||||
WriteEnabled = 0x02,
|
WriteEnabled = 0x02,
|
||||||
ReadEnabled = 0x01
|
ReadEnabled = 0x01
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum StorageType {
|
||||||
|
SeedlingFile = 0x01,
|
||||||
|
SaplingFile = 0x02,
|
||||||
|
TreeFile = 0x03,
|
||||||
|
PascalFile = 0x04,
|
||||||
|
ExtendedFile = 0x05,
|
||||||
|
|
||||||
|
DirectoryFile = 0x0d,
|
||||||
|
DirectoryHeader = 0x0e,
|
||||||
|
VolumeHeader = 0x0f
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class Entry {
|
class Entry {
|
||||||
public:
|
public:
|
||||||
virtual ~Entry();
|
virtual ~Entry();
|
||||||
|
|
||||||
|
virtual void write(Buffer *) = 0;
|
||||||
|
|
||||||
|
|
||||||
unsigned storageType() const { return _storageType; }
|
unsigned storageType() const { return _storageType; }
|
||||||
|
|
||||||
unsigned nameLength() const { return _nameLength; }
|
unsigned nameLength() const { return _nameLength; }
|
||||||
const char *name() const { return _name; }
|
const char *name() const { return _name; }
|
||||||
|
const char *namei() const { return _namei; }
|
||||||
|
|
||||||
|
unsigned caseFlags() const { return _caseFlags; }
|
||||||
|
|
||||||
|
|
||||||
void setName(const char *name);
|
void setName(const char *name);
|
||||||
|
|
||||||
|
|
||||||
|
@ -43,6 +62,20 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Entry(int storageType, const char *name);
|
Entry(int storageType, const char *name);
|
||||||
|
Entry(const void *bp);
|
||||||
|
|
||||||
|
|
||||||
|
setStorageType(unsigned type)
|
||||||
|
{
|
||||||
|
_storageType = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
setAddress(unsigned address)
|
||||||
|
{
|
||||||
|
_address = address;
|
||||||
|
}
|
||||||
|
|
||||||
|
Volume *volume() { return _volume; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -51,11 +84,13 @@ private:
|
||||||
|
|
||||||
unsigned _storageType;
|
unsigned _storageType;
|
||||||
unsigned _nameLength;
|
unsigned _nameLength;
|
||||||
|
char _namei[15+1]; // insensitive, ie, uppercase.
|
||||||
char _name[15+1];
|
char _name[15+1];
|
||||||
|
|
||||||
|
unsigned _caseFlag;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Directory public Entry {
|
class Directory : public Entry {
|
||||||
public:
|
public:
|
||||||
virtual ~Directory();
|
virtual ~Directory();
|
||||||
|
|
||||||
|
@ -68,24 +103,24 @@ public:
|
||||||
|
|
||||||
unsigned fileCount() const { return _fileCount; }
|
unsigned fileCount() const { return _fileCount; }
|
||||||
|
|
||||||
|
unsigned version() const { return _version; }
|
||||||
|
unsigned minVersion() const { return _minVersion; }
|
||||||
|
|
||||||
void setAccess(unsigned access);
|
void setAccess(unsigned access);
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Directory(unsigned type, const char *name);
|
Directory(unsigned type, const char *name);
|
||||||
Directory(BlockDevice *, unsigned block);
|
Directory(const void *bp);
|
||||||
|
|
||||||
std::vector<FileEntry *> _children;
|
std::vector<FileEntry *> _children;
|
||||||
std::vector<unsigned> _entryBlocks;
|
std::vector<unsigned> _entryBlocks;
|
||||||
|
|
||||||
BlockDevice *_device;
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
DateTime _creation;
|
DateTime _creation;
|
||||||
// version
|
unsigned _version
|
||||||
// min version
|
unsigned _minVersion
|
||||||
unsigned _access;
|
unsigned _access;
|
||||||
usnigned _entryLength; // always 0x27
|
usnigned _entryLength; // always 0x27
|
||||||
unsigned _entriesPerBlock; //always 0x0d
|
unsigned _entriesPerBlock; //always 0x0d
|
||||||
|
|
|
@ -0,0 +1,219 @@
|
||||||
|
#ifndef __ENDIAN_H__
|
||||||
|
#define __ENDIAN_H__
|
||||||
|
|
||||||
|
// utlities to read/write bytes.
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
namespace LittleEndian {
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t Read8(const void *vp)
|
||||||
|
{
|
||||||
|
const uint8_t *p = (const uint8_t *)vp;
|
||||||
|
return (p[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Read16(const void *vp)
|
||||||
|
{
|
||||||
|
const uint8_t *p = (const uint8_t *)vp;
|
||||||
|
return p[0] | (p[1] << 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Read24(const void *vp)
|
||||||
|
{
|
||||||
|
const uint8_t *p = (const uint8_t *)vp;
|
||||||
|
return (p[0]) | (p[1] << 8) | (p[2] << 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t Read32(const void *vp)
|
||||||
|
{
|
||||||
|
const uint8_t *p = (const uint8_t *)vp;
|
||||||
|
return (p[0]) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t Read8(const void *vp, unsigned offset)
|
||||||
|
{
|
||||||
|
return Read8(offset + (const uint8_t *)vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Read16(const void *vp, unsigned offset)
|
||||||
|
{
|
||||||
|
return Read16(offset + (const uint8_t *)vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Read24(const void *vp, unsigned offset)
|
||||||
|
{
|
||||||
|
return Read24(offset + (const uint8_t *)vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Read32(const void *vp, unsigned offset)
|
||||||
|
{
|
||||||
|
return Read32(offset + (const uint8_t *)vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// write
|
||||||
|
void Write8(void *vp, uint8_t x)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)vp;
|
||||||
|
p[0] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write16(void *vp, uint16_t x)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)vp;
|
||||||
|
p[0] = (x) & 0xff;
|
||||||
|
p[1] = (x >> 8) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write24(void *vp, uint32_t x)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)vp;
|
||||||
|
p[0] = (x) & 0xff;
|
||||||
|
p[1] = (x >> 8) & 0xff;
|
||||||
|
p[2] = (x >> 16) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write32(void *vp, uint32_t x)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)vp;
|
||||||
|
p[0] = (x) & 0xff;
|
||||||
|
p[1] = (x >> 8) & 0xff;
|
||||||
|
p[2] = (x >> 16) & 0xff;
|
||||||
|
p[3] = (x >> 24) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write8(void *vp, unsigned offset, uint8_t x)
|
||||||
|
{
|
||||||
|
Write8(offset + (uint8_t *)vp, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write16(void *vp, unsigned offset, uint16_t x)
|
||||||
|
{
|
||||||
|
Write16(offset + (uint8_t *)vp, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write24(void *vp, unsigned offset, uint32_t x)
|
||||||
|
{
|
||||||
|
Write24(offset + (uint8_t *)vp, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write32(void *vp, unsigned offset, uint32_t x)
|
||||||
|
{
|
||||||
|
Write32(offset + (uint8_t *)vp, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
namespace BigEndian {
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t Read8(const void *vp)
|
||||||
|
{
|
||||||
|
const uint8_t *p = (const uint8_t *)vp;
|
||||||
|
return p[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Read16(const void *vp)
|
||||||
|
{
|
||||||
|
const uint8_t *p = (const uint8_t *)vp;
|
||||||
|
return (p[0] << 8) | (p[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Read24(const void *vp)
|
||||||
|
{
|
||||||
|
const uint8_t *p = (const uint8_t *)vp;
|
||||||
|
return (p[0] << 16) | (p[1] << 8) | (p[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint32_t Read32(const void *vp)
|
||||||
|
{
|
||||||
|
const uint8_t *p = (const uint8_t *)vp;
|
||||||
|
return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t Read8(const void *vp, unsigned offset)
|
||||||
|
{
|
||||||
|
return Read8(offset + (const uint8_t *)vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t Read16(const void *vp, unsigned offset)
|
||||||
|
{
|
||||||
|
return Read16(offset + (const uint8_t *)vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Read24(const void *vp, unsigned offset)
|
||||||
|
{
|
||||||
|
return Read24(offset + (const uint8_t *)vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Read32(const void *vp, unsigned offset)
|
||||||
|
{
|
||||||
|
return Read32(offset + (const uint8_t *)vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// write
|
||||||
|
void Write8(void *vp, uint8_t x)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)vp;
|
||||||
|
p[0] = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write16(void *vp, uint16_t x)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)vp;
|
||||||
|
p[0] = (x >> 8) & 0xff;
|
||||||
|
p[1] = (x) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write24(void *vp, uint32_t x)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)vp;
|
||||||
|
p[0] = (x >> 16) & 0xff;
|
||||||
|
p[1] = (x >> 8) & 0xff;
|
||||||
|
p[2] = (x) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write32(void *vp, uint32_t x)
|
||||||
|
{
|
||||||
|
uint8_t *p = (uint8_t *)vp;
|
||||||
|
p[0] = (x >> 24) & 0xff;
|
||||||
|
p[1] = (x >> 16) & 0xff;
|
||||||
|
p[2] = (x >> 8) & 0xff;
|
||||||
|
p[3] = (x) & 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write8(void *vp, unsigned offset, uint8_t x)
|
||||||
|
{
|
||||||
|
Write8(offset + (uint8_t *)vp, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write16(void *vp, unsigned offset, uint16_t x)
|
||||||
|
{
|
||||||
|
Write16(offset + (uint8_t *)vp, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write24(void *vp, unsigned offset, uint32_t x)
|
||||||
|
{
|
||||||
|
Write24(offset + (uint8_t *)vp, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Write32(void *vp, unsigned offset, uint32_t x)
|
||||||
|
{
|
||||||
|
Write32(offset + (uint8_t *)vp, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue