mirror of
https://github.com/ksherlock/profuse.git
synced 2024-06-07 12:29:32 +00:00
git-svn-id: https://profuse.googlecode.com/svn/branches/v2@117 aa027e90-d47c-11dd-86d7-074df07e0730
This commit is contained in:
parent
6f6338bc19
commit
736746052b
409
Directory.cpp
409
Directory.cpp
|
@ -2,7 +2,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "Directory"
|
#include "Entry.h"
|
||||||
#include "Buffer.h"
|
#include "Buffer.h"
|
||||||
#include "Endian.h"
|
#include "Endian.h"
|
||||||
|
|
||||||
|
@ -12,154 +12,6 @@
|
||||||
using namespace ProFUSE;
|
using namespace ProFUSE;
|
||||||
using namespace LittleEndian;
|
using namespace LittleEndian;
|
||||||
|
|
||||||
static bool isalpha(unsigned c)
|
|
||||||
{
|
|
||||||
return (c >= 'A' && c <= 'Z')
|
|
||||||
|| (c >= 'a' && x <= 'z') ;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isalnumdot(unsigned c)
|
|
||||||
{
|
|
||||||
return (c >= 'A' && c <= 'Z')
|
|
||||||
|| (c >= 'a' && c <= 'z')
|
|
||||||
|| (c >= '0' && c <='9')
|
|
||||||
|| (c == '.') ;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool islower(unsigned c)
|
|
||||||
{
|
|
||||||
return c >= 'a' && c <= 'z';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ProDOS names:
|
|
||||||
* 1-15 letters, digits, or '.'
|
|
||||||
* first character must be a letter.
|
|
||||||
*/
|
|
||||||
unsigned Entry::ValidName(const char *name)
|
|
||||||
{
|
|
||||||
unsigned length;
|
|
||||||
|
|
||||||
if (!name) return 0;
|
|
||||||
|
|
||||||
if (!isalpha(*name)) return 0;
|
|
||||||
length = 1;
|
|
||||||
|
|
||||||
for (length = 1; length < 17; ++length)
|
|
||||||
{
|
|
||||||
if (!isalnumdot(name[length])) return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (length > 15) return 0;
|
|
||||||
return length;
|
|
||||||
}
|
|
||||||
|
|
||||||
Entry::Entry(unsigned type, const char *name)
|
|
||||||
{
|
|
||||||
_storageType = type;
|
|
||||||
_address = 0;
|
|
||||||
_index = 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;
|
|
||||||
_index = 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) :
|
Directory::Directory(unsigned type, const char *name) :
|
||||||
|
@ -186,7 +38,7 @@ Directory::Directory(const void *bp) :
|
||||||
|
|
||||||
// input is a block pointer. To simplify,
|
// input is a block pointer. To simplify,
|
||||||
// create a new pointer past the 4-byte linked list part.
|
// create a new pointer past the 4-byte linked list part.
|
||||||
void *dp = 4 + (const uint8_t *)bp;
|
const void *dp = 4 + (const uint8_t *)bp;
|
||||||
|
|
||||||
_creation = DateTime(Read16(dp, 0x18), Read16(dp, 0x1a));
|
_creation = DateTime(Read16(dp, 0x18), Read16(dp, 0x1a));
|
||||||
|
|
||||||
|
@ -197,7 +49,7 @@ Directory::Directory(const void *bp) :
|
||||||
_entryLength = Read8(dp, 0x1f);
|
_entryLength = Read8(dp, 0x1f);
|
||||||
_entriesPerBlock = Read8(dp, 0x20);
|
_entriesPerBlock = Read8(dp, 0x20);
|
||||||
|
|
||||||
_fileCount = read16(dp, 0x21);
|
_fileCount = Read16(dp, 0x21);
|
||||||
|
|
||||||
// parse child file entries ... requires ability to read other blocks.
|
// parse child file entries ... requires ability to read other blocks.
|
||||||
}
|
}
|
||||||
|
@ -206,265 +58,14 @@ Directory::~Directory()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
Directory::setAccess(unsigned access)
|
void Directory::setAccess(unsigned access)
|
||||||
{
|
{
|
||||||
#undef __METHOD__
|
#undef __METHOD__
|
||||||
#define __METHOD__ "Directory::setAccess"
|
#define __METHOD__ "Directory::setAccess"
|
||||||
|
|
||||||
if ((access & 0xe7) != access)
|
|
||||||
throw Exception(__METHOD__ ": Illegal access.");
|
|
||||||
_access = access;
|
_access = access;
|
||||||
|
|
||||||
// todo -- mark dirty? update block?
|
// todo -- mark dirty? update block?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#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(FileEntry *e) :
|
|
||||||
Directory(DirectoryHeader, e->iname())
|
|
||||||
{
|
|
||||||
_creation = e->creation();
|
|
||||||
setAccess(e->access());
|
|
||||||
|
|
||||||
_parentEntryPointer = e->block();
|
|
||||||
_parentEntryNumber = e->index();
|
|
||||||
_parentEntryLength = 0x27;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
SubDirectory::SubDirectory(const char *name) :
|
|
||||||
Directory(DirectoryHeader, 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);
|
|
||||||
}
|
|
169
Entry.cpp
Normal file
169
Entry.cpp
Normal file
|
@ -0,0 +1,169 @@
|
||||||
|
#include "Entry.h"
|
||||||
|
#include "Endian.h"
|
||||||
|
#include "Buffer.h"
|
||||||
|
#include "Exception.h"
|
||||||
|
|
||||||
|
using namespace ProFUSE;
|
||||||
|
using namespace LittleEndian;
|
||||||
|
|
||||||
|
// do it ourselves since could be different locale or something.
|
||||||
|
#undef isalpha
|
||||||
|
#undef isalnumdot
|
||||||
|
#undef islower
|
||||||
|
#undef tolower
|
||||||
|
#undef toupper
|
||||||
|
|
||||||
|
static bool isalpha(char c)
|
||||||
|
{
|
||||||
|
return (c >= 'A' && c <= 'Z')
|
||||||
|
|| (c >= 'a' && c <= 'z') ;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isalnumdot(char c)
|
||||||
|
{
|
||||||
|
return (c >= 'A' && c <= 'Z')
|
||||||
|
|| (c >= 'a' && c <= 'z')
|
||||||
|
|| (c >= '0' && c <='9')
|
||||||
|
|| (c == '.') ;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool islower(char c)
|
||||||
|
{
|
||||||
|
return c >= 'a' && c <= 'z';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
inline char tolower(char c) { return c | 0x20; }
|
||||||
|
inline char toupper(char c) { return c & ~0x20; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ProDOS names:
|
||||||
|
* 1-15 letters, digits, or '.'
|
||||||
|
* first character must be a letter.
|
||||||
|
*/
|
||||||
|
unsigned Entry::ValidName(const char *name)
|
||||||
|
{
|
||||||
|
unsigned length = 1;
|
||||||
|
|
||||||
|
if (!name) return 0;
|
||||||
|
|
||||||
|
if (!isalpha(*name)) return 0;
|
||||||
|
|
||||||
|
for (length = 1; length < 17; ++length)
|
||||||
|
{
|
||||||
|
if (!isalnumdot(name[length])) return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (length > 15) return 0;
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Entry::Entry(unsigned type, const char *name)
|
||||||
|
{
|
||||||
|
_address = 0;
|
||||||
|
_index = 0;
|
||||||
|
_volume = NULL;
|
||||||
|
_nameLength = 0;
|
||||||
|
_caseFlag = 0;
|
||||||
|
_storageType = type;
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
_index = 0;
|
||||||
|
_volume = NULL;
|
||||||
|
|
||||||
|
_caseFlag = 0;
|
||||||
|
_nameLength = 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] = tolower(_name[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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] = toupper(c);
|
||||||
|
if (islower(c))
|
||||||
|
{
|
||||||
|
caseFlag |= (0x4000 >> i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_nameLength = length;
|
||||||
|
_caseFlag = caseFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
48
Entry.h
48
Entry.h
|
@ -52,7 +52,7 @@ public:
|
||||||
const char *name() const { return _name; }
|
const char *name() const { return _name; }
|
||||||
const char *namei() const { return _namei; }
|
const char *namei() const { return _namei; }
|
||||||
|
|
||||||
unsigned caseFlags() const { return _caseFlags; }
|
unsigned caseFlag() const { return _caseFlag; }
|
||||||
|
|
||||||
|
|
||||||
void setName(const char *name);
|
void setName(const char *name);
|
||||||
|
@ -63,37 +63,33 @@ public:
|
||||||
static unsigned ValidName(const char *);
|
static unsigned ValidName(const char *);
|
||||||
|
|
||||||
|
|
||||||
unsigned block() const { return _address / 512; }
|
unsigned block() const { return _address / 512; }
|
||||||
unsigned offset() const { return _address % 512; }
|
unsigned offset() const { return _address % 512; }
|
||||||
|
|
||||||
unsigned address() const { return _address; }
|
unsigned address() const { return _address; }
|
||||||
|
|
||||||
unsigned index() const { return _index; }
|
unsigned index() const { return _index; }
|
||||||
|
|
||||||
|
Volume *volume() { return _volume; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Entry(int storageType, const char *name);
|
Entry(unsigned storageType, const char *name);
|
||||||
Entry(const void *bp);
|
Entry(const void *bp);
|
||||||
|
|
||||||
|
|
||||||
setStorageType(unsigned type)
|
void setStorageType(unsigned type)
|
||||||
{
|
{ _storageType = type; }
|
||||||
_storageType = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void setAddress(unsigned address)
|
||||||
|
{ _address = address; }
|
||||||
|
|
||||||
setAddress(unsigned address)
|
void setIndex(unsigned index)
|
||||||
{
|
{ _index = index; }
|
||||||
_address = address;
|
|
||||||
}
|
|
||||||
|
|
||||||
setIndex(unsigned index)
|
|
||||||
{
|
|
||||||
_index = index;w
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
void setVolume(Volume *v)
|
||||||
Volume *volume() { return _volume; }
|
{ _volume = v; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -101,7 +97,7 @@ private:
|
||||||
unsigned _index;
|
unsigned _index;
|
||||||
|
|
||||||
Volume *_volume;
|
Volume *_volume;
|
||||||
|
|
||||||
unsigned _storageType;
|
unsigned _storageType;
|
||||||
unsigned _nameLength;
|
unsigned _nameLength;
|
||||||
char _namei[15+1]; // insensitive, ie, uppercase.
|
char _namei[15+1]; // insensitive, ie, uppercase.
|
||||||
|
@ -139,8 +135,8 @@ protected:
|
||||||
private:
|
private:
|
||||||
|
|
||||||
DateTime _creation;
|
DateTime _creation;
|
||||||
unsigned _version
|
unsigned _version;
|
||||||
unsigned _minVersion
|
unsigned _minVersion;
|
||||||
unsigned _access;
|
unsigned _access;
|
||||||
unsigned _entryLength; // always 0x27
|
unsigned _entryLength; // always 0x27
|
||||||
unsigned _entriesPerBlock; //always 0x0d
|
unsigned _entriesPerBlock; //always 0x0d
|
||||||
|
@ -153,6 +149,7 @@ private:
|
||||||
class VolumeDirectory: public Directory {
|
class VolumeDirectory: public Directory {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
VolumeDirectory(const char *name, BlockDevice *device);
|
||||||
virtual ~VolumeDirectory();
|
virtual ~VolumeDirectory();
|
||||||
|
|
||||||
unsigned bitmapPointer() const { return _bitmapPointer; }
|
unsigned bitmapPointer() const { return _bitmapPointer; }
|
||||||
|
@ -162,12 +159,17 @@ public:
|
||||||
int allocBlock();
|
int allocBlock();
|
||||||
void freeBlock(unsigned block);
|
void freeBlock(unsigned block);
|
||||||
|
|
||||||
|
virtual void write(Buffer *);
|
||||||
|
|
||||||
|
BlockDevice *device() const { return _device; }
|
||||||
private:
|
private:
|
||||||
Bitmap *_bitmap;
|
Bitmap *_bitmap;
|
||||||
|
BlockDevice *_device;
|
||||||
|
|
||||||
|
DateTime _modification;
|
||||||
unsigned _totalBlocks;
|
unsigned _totalBlocks;
|
||||||
unsigned _bitmapPointer;
|
unsigned _bitmapPointer;
|
||||||
|
|
||||||
// inode / free inode list?
|
// inode / free inode list?
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
119
VolumeDirectory.cpp
Normal file
119
VolumeDirectory.cpp
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include "Bitmap.h"
|
||||||
|
#include "BlockDevice.h"
|
||||||
|
#include "Buffer.h"
|
||||||
|
#include "Endian.h"
|
||||||
|
#include "Entry.h"
|
||||||
|
#include "Exception.h"
|
||||||
|
|
||||||
|
using namespace ProFUSE;
|
||||||
|
using namespace LittleEndian;
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark VolumeDirectory
|
||||||
|
|
||||||
|
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));
|
||||||
|
|
||||||
|
Buffer buffer(512);
|
||||||
|
|
||||||
|
// 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(&buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.resize(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->write(_bitmapPointer + i, 512 * i + bm);
|
||||||
|
}
|
||||||
|
|
||||||
|
_device = device;
|
||||||
|
_bitmap = bitmap.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
VolumeDirectory::~VolumeDirectory()
|
||||||
|
{
|
||||||
|
if (_device)
|
||||||
|
{
|
||||||
|
_device->sync();
|
||||||
|
delete _device;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user