From 736746052b9ae912373581159393e9ee9b65f9f4 Mon Sep 17 00:00:00 2001 From: ksherlock Date: Thu, 26 Nov 2009 19:30:12 +0000 Subject: [PATCH] git-svn-id: https://profuse.googlecode.com/svn/branches/v2@117 aa027e90-d47c-11dd-86d7-074df07e0730 --- Directory.cpp | 409 +------------------------------------------- Entry.cpp | 169 ++++++++++++++++++ Entry.h | 48 +++--- VolumeDirectory.cpp | 119 +++++++++++++ 4 files changed, 318 insertions(+), 427 deletions(-) create mode 100644 Entry.cpp create mode 100644 VolumeDirectory.cpp diff --git a/Directory.cpp b/Directory.cpp index 48c2af5..04ee1ed 100644 --- a/Directory.cpp +++ b/Directory.cpp @@ -2,7 +2,7 @@ #include #include -#include "Directory" +#include "Entry.h" #include "Buffer.h" #include "Endian.h" @@ -12,154 +12,6 @@ using namespace ProFUSE; 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) : @@ -186,7 +38,7 @@ Directory::Directory(const void *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; + const void *dp = 4 + (const uint8_t *)bp; _creation = DateTime(Read16(dp, 0x18), Read16(dp, 0x1a)); @@ -197,7 +49,7 @@ Directory::Directory(const void *bp) : _entryLength = Read8(dp, 0x1f); _entriesPerBlock = Read8(dp, 0x20); - _fileCount = read16(dp, 0x21); + _fileCount = Read16(dp, 0x21); // 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__ #define __METHOD__ "Directory::setAccess" - if ((access & 0xe7) != access) - throw Exception(__METHOD__ ": Illegal access."); + _access = access; // 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(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); -} \ No newline at end of file diff --git a/Entry.cpp b/Entry.cpp new file mode 100644 index 0000000..15b84b1 --- /dev/null +++ b/Entry.cpp @@ -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; +} + + diff --git a/Entry.h b/Entry.h index 64cd21a..3ff3d39 100644 --- a/Entry.h +++ b/Entry.h @@ -52,7 +52,7 @@ public: const char *name() const { return _name; } const char *namei() const { return _namei; } - unsigned caseFlags() const { return _caseFlags; } + unsigned caseFlag() const { return _caseFlag; } void setName(const char *name); @@ -63,37 +63,33 @@ public: static unsigned ValidName(const char *); - unsigned block() const { return _address / 512; } + unsigned block() const { return _address / 512; } unsigned offset() const { return _address % 512; } unsigned address() const { return _address; } unsigned index() const { return _index; } + + Volume *volume() { return _volume; } protected: - Entry(int storageType, const char *name); + Entry(unsigned storageType, const char *name); Entry(const void *bp); - setStorageType(unsigned type) - { - _storageType = type; - } + void setStorageType(unsigned type) + { _storageType = type; } + void setAddress(unsigned address) + { _address = address; } - setAddress(unsigned address) - { - _address = address; - } - - setIndex(unsigned index) - { - _index = index;w - } - + void setIndex(unsigned index) + { _index = index; } - - Volume *volume() { return _volume; } + void setVolume(Volume *v) + { _volume = v; } + + private: @@ -101,7 +97,7 @@ private: unsigned _index; Volume *_volume; - + unsigned _storageType; unsigned _nameLength; char _namei[15+1]; // insensitive, ie, uppercase. @@ -139,8 +135,8 @@ protected: private: DateTime _creation; - unsigned _version - unsigned _minVersion + unsigned _version; + unsigned _minVersion; unsigned _access; unsigned _entryLength; // always 0x27 unsigned _entriesPerBlock; //always 0x0d @@ -153,6 +149,7 @@ private: class VolumeDirectory: public Directory { public: + VolumeDirectory(const char *name, BlockDevice *device); virtual ~VolumeDirectory(); unsigned bitmapPointer() const { return _bitmapPointer; } @@ -162,12 +159,17 @@ public: int allocBlock(); void freeBlock(unsigned block); + virtual void write(Buffer *); + + BlockDevice *device() const { return _device; } private: Bitmap *_bitmap; + BlockDevice *_device; + DateTime _modification; unsigned _totalBlocks; unsigned _bitmapPointer; - + // inode / free inode list? }; diff --git a/VolumeDirectory.cpp b/VolumeDirectory.cpp new file mode 100644 index 0000000..20f0c63 --- /dev/null +++ b/VolumeDirectory.cpp @@ -0,0 +1,119 @@ + +#include +#include + +#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(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); +}