2009-12-16 01:33:28 +00:00
|
|
|
#include <Device/UniversalDiskImage.h>
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2009-12-16 01:33:28 +00:00
|
|
|
#include <Endian/Endian.h>
|
|
|
|
#include <Endian/IOBuffer.h>
|
|
|
|
|
|
|
|
#include <ProFUSE/Exception.h>
|
|
|
|
|
2010-05-18 19:59:18 +00:00
|
|
|
#include <Cache/MappedBlockCache.h>
|
|
|
|
#include <Cache/ConcreteBlockCache.h>
|
|
|
|
|
2009-12-16 01:33:28 +00:00
|
|
|
using namespace Device;
|
2009-11-23 22:36:05 +00:00
|
|
|
using namespace LittleEndian;
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2009-12-16 01:33:28 +00:00
|
|
|
using ProFUSE::Exception;
|
|
|
|
using ProFUSE::POSIXException;
|
|
|
|
|
2010-05-18 19:59:18 +00:00
|
|
|
|
|
|
|
|
2010-05-18 02:58:26 +00:00
|
|
|
/*
|
2009-11-21 01:45:08 +00:00
|
|
|
UniversalDiskImage::UniversalDiskImage(const char *name, bool readOnly) :
|
|
|
|
DiskImage(name, readOnly)
|
|
|
|
{
|
|
|
|
Validate(file());
|
2009-11-23 22:36:05 +00:00
|
|
|
const void *data = file()->fileData();
|
|
|
|
|
|
|
|
// flags. bit 31 = locked.
|
2009-11-24 04:36:48 +00:00
|
|
|
_flags = Read32(data, 0x10);
|
2009-11-21 01:45:08 +00:00
|
|
|
}
|
2010-05-18 02:58:26 +00:00
|
|
|
*/
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
UniversalDiskImage::UniversalDiskImage(MappedFile *file) :
|
|
|
|
DiskImage(file)
|
|
|
|
{
|
2010-05-18 02:58:26 +00:00
|
|
|
|
2010-05-19 17:50:18 +00:00
|
|
|
// at this point, file is no longer valid.
|
|
|
|
|
|
|
|
uint8_t * data = (uint8_t *)address();
|
2010-05-18 02:58:26 +00:00
|
|
|
|
2010-05-18 19:59:18 +00:00
|
|
|
|
2010-05-18 02:58:26 +00:00
|
|
|
|
|
|
|
|
2010-05-18 19:59:18 +00:00
|
|
|
_format = Read32(data, 0x0c);
|
2010-05-18 02:58:26 +00:00
|
|
|
_flags = Read32(data, 0x10);
|
2010-05-18 19:59:18 +00:00
|
|
|
_blocks = Read32(data, 0x14);
|
2010-05-18 02:58:26 +00:00
|
|
|
|
2010-05-18 19:59:18 +00:00
|
|
|
_dataOffset = Read32(data, 0x18);
|
|
|
|
_dataLength = Read32(data, 0x1c);
|
2010-05-18 02:58:26 +00:00
|
|
|
|
2010-05-18 19:59:18 +00:00
|
|
|
|
|
|
|
setBlocks(_blocks);
|
2010-05-18 02:58:26 +00:00
|
|
|
// TODO -- DO, Nibble support.
|
2010-05-18 19:59:18 +00:00
|
|
|
setAdaptor(new POAdaptor(_dataOffset + data));
|
2009-11-21 01:45:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
UniversalDiskImage *UniversalDiskImage::Create(const char *name, size_t blocks)
|
|
|
|
{
|
|
|
|
// 64-byte header.
|
|
|
|
MappedFile *file = new MappedFile(name, blocks * 512 + 64);
|
|
|
|
|
2009-12-16 01:33:28 +00:00
|
|
|
uint8_t tmp[64];
|
|
|
|
|
|
|
|
IOBuffer header(tmp, 64);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
// magic + creator
|
2009-12-16 01:33:28 +00:00
|
|
|
header.writeBytes("2IMGPRFS", 8);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// header size.
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write16(64);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// version
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write16(1);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
//image format -- ProDOS order
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write32(1);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// flags
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write32(0);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// # blocks. s/b 0 unless prodos-order
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write32(blocks);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// offset to disk data
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write32(64);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// data length
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write32(512 * blocks);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// comment offset, creator, reserved -- 0.
|
2009-12-16 01:33:28 +00:00
|
|
|
header.setOffset(64, true);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2010-05-18 02:58:26 +00:00
|
|
|
std::memcpy(file->address(), header.buffer(), 64);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
|
|
|
|
return new UniversalDiskImage(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
UniversalDiskImage *UniversalDiskImage::Open(MappedFile *file)
|
|
|
|
{
|
|
|
|
Validate(file);
|
|
|
|
return new UniversalDiskImage(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* TODO -- support dos-order & nibblized
|
|
|
|
* TODO -- honor read-only flag.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
void UniversalDiskImage::Validate(MappedFile *file)
|
|
|
|
{
|
|
|
|
#undef __METHOD__
|
2009-11-26 15:58:10 +00:00
|
|
|
#define __METHOD__ "UniversalDiskImage::Validate"
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2010-05-18 02:58:26 +00:00
|
|
|
const void *data = file->address();
|
|
|
|
size_t size = file->length();
|
2009-11-21 01:45:08 +00:00
|
|
|
bool ok = false;
|
|
|
|
unsigned blocks = 0;
|
|
|
|
unsigned offset = 0;
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
|
|
|
if (size < 64) break;
|
|
|
|
|
|
|
|
if (std::memcmp(data, "2IMG", 4)) break;
|
|
|
|
|
|
|
|
// only prodos supported, for now...
|
2010-05-18 02:58:26 +00:00
|
|
|
// TODO -- Dos Order, Nibble support.
|
2009-11-23 22:36:05 +00:00
|
|
|
if (Read32(data, 0x0c) != 1) break;
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2009-11-23 22:36:05 +00:00
|
|
|
blocks = Read32(data, 0x14);
|
2010-05-18 19:59:18 +00:00
|
|
|
offset = Read32(data, 0x18);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// file size == blocks * 512
|
2009-11-23 22:36:05 +00:00
|
|
|
if (Read32(data, 0x1c) != blocks * 512) break;
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
if (offset + blocks * 512 > size) break;
|
|
|
|
|
|
|
|
ok = true;
|
|
|
|
} while (false);
|
|
|
|
|
|
|
|
if (!ok)
|
|
|
|
throw Exception(__METHOD__ ": Invalid file format.");
|
|
|
|
|
2010-05-18 02:58:26 +00:00
|
|
|
|
2009-11-23 22:36:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool UniversalDiskImage::readOnly()
|
|
|
|
{
|
|
|
|
return (_flags & 0x8000000) || DiskImage::readOnly();
|
2010-05-18 19:59:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-18 21:26:07 +00:00
|
|
|
BlockCache *UniversalDiskImage::createBlockCache()
|
2010-05-18 19:59:18 +00:00
|
|
|
{
|
|
|
|
if (_format == 1)
|
|
|
|
{
|
|
|
|
return new MappedBlockCache(this, _dataOffset + (uint8_t *)address());
|
|
|
|
}
|
|
|
|
|
2010-05-18 21:26:07 +00:00
|
|
|
return DiskImage::createBlockCache();
|
2010-05-18 19:59:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|