2009-12-16 01:33:28 +00:00
|
|
|
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2009-11-24 03:56:19 +00:00
|
|
|
#include <cstdio>
|
2009-11-26 15:58:10 +00:00
|
|
|
#include <cstring>
|
|
|
|
#include <algorithm>
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2009-12-16 01:33:28 +00:00
|
|
|
#include <Device/DiskCopy42Image.h>
|
|
|
|
|
|
|
|
#include <Endian/Endian.h>
|
|
|
|
#include <Endian/IOBuffer.h>
|
|
|
|
|
2010-05-18 19:59:18 +00:00
|
|
|
#include <Cache/MappedBlockCache.h>
|
|
|
|
|
|
|
|
|
2009-12-16 01:33:28 +00:00
|
|
|
using namespace Device;
|
2009-11-24 03:56:19 +00:00
|
|
|
using namespace BigEndian;
|
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 02:58:26 +00:00
|
|
|
|
2010-05-18 19:59:18 +00:00
|
|
|
|
2010-05-18 02:58:26 +00:00
|
|
|
enum {
|
|
|
|
oDataSize = 64,
|
|
|
|
oDataChecksum = 72,
|
|
|
|
oPrivate = 82,
|
|
|
|
oUserData = 84
|
|
|
|
};
|
|
|
|
|
2009-11-21 01:45:08 +00:00
|
|
|
DiskCopy42Image::DiskCopy42Image(MappedFile *f) :
|
|
|
|
DiskImage(f),
|
|
|
|
_changed(false)
|
|
|
|
{
|
2010-05-18 02:58:26 +00:00
|
|
|
setAdaptor(new POAdaptor(oUserData + (uint8_t *)f->address()));
|
|
|
|
setBlocks(Read32(f->address(), oDataSize) / 512);
|
2009-11-21 01:45:08 +00:00
|
|
|
}
|
|
|
|
|
2010-05-18 02:58:26 +00:00
|
|
|
|
|
|
|
/*
|
2009-11-21 01:45:08 +00:00
|
|
|
DiskCopy42Image::DiskCopy42Image(const char *name, bool readOnly) :
|
|
|
|
DiskImage(name, readOnly),
|
|
|
|
_changed(false)
|
|
|
|
{
|
|
|
|
Validate(file());
|
|
|
|
}
|
2010-05-18 02:58:26 +00:00
|
|
|
*/
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
DiskCopy42Image::~DiskCopy42Image()
|
|
|
|
{
|
|
|
|
if (_changed)
|
|
|
|
{
|
|
|
|
MappedFile *f = file();
|
2009-11-24 03:56:19 +00:00
|
|
|
|
2009-11-21 01:45:08 +00:00
|
|
|
if (f)
|
|
|
|
{
|
2010-05-18 02:58:26 +00:00
|
|
|
void *data = f->address();
|
|
|
|
|
|
|
|
uint32_t cs = Checksum(oUserData + (uint8_t *)data, Read32(data, oDataSize));
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2010-05-18 02:58:26 +00:00
|
|
|
Write32(data, oDataChecksum, cs);
|
2009-11-21 01:45:08 +00:00
|
|
|
f->sync();
|
|
|
|
}
|
|
|
|
// TODO -- checksum
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t DiskCopy42Image::Checksum(void *data, size_t size)
|
|
|
|
{
|
|
|
|
uint32_t rv = 0;
|
|
|
|
uint8_t *dp = (uint8_t *)data;
|
|
|
|
|
|
|
|
if (size & 0x01) return rv;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < size; i += 2)
|
|
|
|
{
|
|
|
|
rv += dp[i] << 8;
|
|
|
|
rv += dp[i+1];
|
|
|
|
|
|
|
|
rv = (rv >> 1) + (rv << 31);
|
|
|
|
}
|
|
|
|
|
|
|
|
return rv;
|
|
|
|
}
|
|
|
|
|
|
|
|
DiskCopy42Image *DiskCopy42Image::Open(MappedFile *f)
|
|
|
|
{
|
|
|
|
Validate(f);
|
|
|
|
return new DiskCopy42Image(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint8_t DiskFormat(size_t blocks)
|
|
|
|
{
|
|
|
|
switch (blocks)
|
|
|
|
{
|
|
|
|
case 800: return 0;
|
|
|
|
case 1600: return 1;
|
|
|
|
case 1440: return 2;
|
|
|
|
case 2880: return 3;
|
|
|
|
default: return 0xff;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint8_t FormatByte(size_t blocks)
|
|
|
|
{
|
|
|
|
switch(blocks)
|
|
|
|
{
|
|
|
|
case 800: return 0x12;
|
|
|
|
default: return 0x22;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DiskCopy42Image *DiskCopy42Image::Create(const char *name, size_t blocks)
|
2009-11-26 15:58:10 +00:00
|
|
|
{
|
|
|
|
return Create(name, blocks, "Untitled");
|
|
|
|
}
|
|
|
|
|
|
|
|
DiskCopy42Image *DiskCopy42Image::Create(const char *name, size_t blocks, const char *vname)
|
2009-11-21 01:45:08 +00:00
|
|
|
{
|
2010-05-18 02:58:26 +00:00
|
|
|
MappedFile *file = new MappedFile(name, blocks * 512 + oUserData);
|
|
|
|
|
|
|
|
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2010-05-18 02:58:26 +00:00
|
|
|
uint8_t tmp[oUserData];
|
|
|
|
IOBuffer header(tmp, oUserData);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2009-11-26 15:58:10 +00:00
|
|
|
// name -- 64byte pstring.
|
|
|
|
|
|
|
|
if (vname == NULL) vname = "Untitled";
|
|
|
|
unsigned l = std::strlen(vname);
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write8(std::min(l, 63u));
|
|
|
|
header.writeBytes(vname, std::min(l, 63u));
|
2009-11-26 15:58:10 +00:00
|
|
|
|
2009-12-16 01:33:28 +00:00
|
|
|
//header.resize(64);
|
2010-05-18 02:58:26 +00:00
|
|
|
header.setOffset(oDataSize, true);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// data size -- number of bytes
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write32(blocks * 512);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// tag size
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write32(0);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// data checksum
|
|
|
|
// if data is 0, will be 0.
|
|
|
|
//header.push32be(Checksum(file->fileData(), blocks * 512));
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write32(0);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// tag checksum
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write32(0);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// disk format.
|
|
|
|
/*
|
|
|
|
* 0 = 400k
|
|
|
|
* 1 = 800k
|
|
|
|
* 2 = 720k
|
|
|
|
* 3 = 1440k
|
|
|
|
* 0xff = other
|
|
|
|
*/
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write8(DiskFormat(blocks));
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// formatbyte
|
|
|
|
/*
|
|
|
|
* 0x12 = 400k
|
|
|
|
* 0x22 = >400k mac
|
|
|
|
* 0x24 = 800k appleII
|
|
|
|
*/
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write8(FormatByte(blocks));
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// private
|
2009-12-16 01:33:28 +00:00
|
|
|
header.write16(0x100);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2010-05-18 02:58:26 +00:00
|
|
|
std::memcpy(file->address(), header.buffer(), oUserData);
|
2009-11-21 01:45:08 +00:00
|
|
|
file->sync();
|
|
|
|
|
|
|
|
return new DiskCopy42Image(file);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DiskCopy42Image::Validate(MappedFile *file)
|
|
|
|
{
|
2009-11-26 15:58:10 +00:00
|
|
|
#undef __METHOD__
|
|
|
|
#define __METHOD__ "DiskCopy42Image::Validate"
|
|
|
|
|
2009-11-21 01:45:08 +00:00
|
|
|
size_t bytes = 0;
|
2010-05-18 02:58:26 +00:00
|
|
|
size_t size = file->length();
|
|
|
|
const void *data = file->address();
|
2009-11-21 01:45:08 +00:00
|
|
|
bool ok = false;
|
2009-11-26 15:58:10 +00:00
|
|
|
uint32_t checksum = 0;
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
do {
|
2010-05-18 02:58:26 +00:00
|
|
|
if (size < oUserData) break;
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// name must be < 64
|
2009-11-24 03:56:19 +00:00
|
|
|
if (Read8(data, 0) > 63) break;
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2010-05-18 02:58:26 +00:00
|
|
|
if (Read32(data, oPrivate) != 0x100)
|
2009-11-21 01:45:08 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
// bytes, not blocks.
|
2010-05-18 02:58:26 +00:00
|
|
|
bytes = Read32(data, oDataSize);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
if (bytes % 512) break;
|
|
|
|
|
2010-05-18 02:58:26 +00:00
|
|
|
if (size < oUserData + bytes) break;
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
// todo -- checksum.
|
2010-05-18 02:58:26 +00:00
|
|
|
checksum = Read32(data, oDataChecksum);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
ok = true;
|
|
|
|
} while (false);
|
|
|
|
|
2009-11-26 15:58:10 +00:00
|
|
|
if (!ok)
|
|
|
|
throw Exception(__METHOD__ ": Invalid file format.");
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2010-05-18 02:58:26 +00:00
|
|
|
uint32_t cs = Checksum(oUserData + (uint8_t *)data, bytes);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
|
|
|
if (cs != checksum)
|
|
|
|
{
|
2010-05-18 02:58:26 +00:00
|
|
|
fprintf(stderr, __METHOD__ ": Warning: checksum invalid.\n");
|
2009-11-21 01:45:08 +00:00
|
|
|
}
|
2010-05-18 02:58:26 +00:00
|
|
|
|
2009-11-21 01:45:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DiskCopy42Image::write(unsigned block, const void *bp)
|
|
|
|
{
|
|
|
|
DiskImage::write(block, bp);
|
|
|
|
_changed = true;
|
2010-05-18 19:59:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-05-18 21:26:07 +00:00
|
|
|
BlockCache *DiskCopy42Image::createBlockCache()
|
2010-05-18 19:59:18 +00:00
|
|
|
{
|
|
|
|
// if not readonly, mark changed so crc will be updated at close.
|
|
|
|
|
|
|
|
if (!readOnly()) _changed = true;
|
|
|
|
|
|
|
|
return new MappedBlockCache(this, address());
|
2009-11-21 01:45:08 +00:00
|
|
|
}
|