mirror of
https://github.com/ksherlock/profuse.git
synced 2024-12-25 08:29:22 +00:00
123 lines
2.6 KiB
C++
123 lines
2.6 KiB
C++
#include "UniversalDiskImage.h"
|
|
#include "MappedFile.h"
|
|
#include "Buffer.h"
|
|
#include "Endian.h"
|
|
|
|
using namespace ProFUSE;
|
|
using namespace LittleEndian;
|
|
|
|
UniversalDiskImage::UniversalDiskImage(const char *name, bool readOnly) :
|
|
DiskImage(name, readOnly)
|
|
{
|
|
Validate(file());
|
|
const void *data = file()->fileData();
|
|
|
|
// flags. bit 31 = locked.
|
|
_flags = Read32(data, 0x10);
|
|
}
|
|
|
|
UniversalDiskImage::UniversalDiskImage(MappedFile *file) :
|
|
DiskImage(file)
|
|
{
|
|
_flags = 0;
|
|
}
|
|
|
|
UniversalDiskImage *UniversalDiskImage::Create(const char *name, size_t blocks)
|
|
{
|
|
// 64-byte header.
|
|
MappedFile *file = new MappedFile(name, blocks * 512 + 64);
|
|
|
|
Buffer header(64);
|
|
|
|
|
|
// magic + creator
|
|
header.pushBytes("2IMGPRFS", 8);
|
|
|
|
// header size.
|
|
header.push16le(64);
|
|
|
|
// version
|
|
header.push16le(1);
|
|
|
|
//image format -- ProDOS order
|
|
header.push32le(1);
|
|
|
|
// flags
|
|
header.push32le(0);
|
|
|
|
// # blocks. s/b 0 unless prodos-order
|
|
header.push32le(blocks);
|
|
|
|
// offset to disk data
|
|
header.push32le(64);
|
|
|
|
// data length
|
|
header.push32le(512 * blocks);
|
|
|
|
// comment offset, creator, reserved -- 0.
|
|
header.resize(64);
|
|
|
|
std::memcpy(file->fileData(), header.buffer(), 64);
|
|
|
|
|
|
file->setOffset(64);
|
|
file->setBlocks(blocks);
|
|
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__
|
|
#define __METHOD__ "UniversalDiskImage::Validate"
|
|
|
|
const void *data = file->fileData();
|
|
size_t size = file->fileSize();
|
|
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...
|
|
if (Read32(data, 0x0c) != 1) break;
|
|
|
|
offset = Read32(data, 0x20);
|
|
blocks = Read32(data, 0x14);
|
|
|
|
// file size == blocks * 512
|
|
if (Read32(data, 0x1c) != blocks * 512) break;
|
|
|
|
if (offset + blocks * 512 > size) break;
|
|
|
|
ok = true;
|
|
} while (false);
|
|
|
|
if (!ok)
|
|
throw Exception(__METHOD__ ": Invalid file format.");
|
|
|
|
file->reset();
|
|
file->setOffset(offset);
|
|
file->setBlocks(blocks);
|
|
}
|
|
|
|
|
|
bool UniversalDiskImage::readOnly()
|
|
{
|
|
return (_flags & 0x8000000) || DiskImage::readOnly();
|
|
} |