mirror of
https://github.com/ksherlock/profuse.git
synced 2024-05-28 22:41:39 +00:00
added SDK support, better validation/sniffing
git-svn-id: https://profuse.googlecode.com/svn/branches/v2@381 aa027e90-d47c-11dd-86d7-074df07e0730
This commit is contained in:
parent
5f893f78fc
commit
32bb5d79b9
|
@ -19,6 +19,7 @@
|
||||||
#include <Device/DiskCopy42Image.h>
|
#include <Device/DiskCopy42Image.h>
|
||||||
#include <Device/DavexDiskImage.h>
|
#include <Device/DavexDiskImage.h>
|
||||||
#include <Device/RawDevice.h>
|
#include <Device/RawDevice.h>
|
||||||
|
#include <Device/SDKImage.h>
|
||||||
|
|
||||||
using namespace Device;
|
using namespace Device;
|
||||||
|
|
||||||
|
@ -26,6 +27,30 @@ using ProFUSE::Exception;
|
||||||
using ProFUSE::POSIXException;
|
using ProFUSE::POSIXException;
|
||||||
|
|
||||||
|
|
||||||
|
unsigned BlockDevice::ImageType(MappedFile *f, unsigned defv)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "BlockDevice::ImageType"
|
||||||
|
|
||||||
|
|
||||||
|
if (UniversalDiskImage::Validate(f, std::nothrow))
|
||||||
|
return '2IMG';
|
||||||
|
|
||||||
|
if (DiskCopy42Image::Validate(f, std::nothrow))
|
||||||
|
return 'DC42';
|
||||||
|
|
||||||
|
if (SDKImage::Validate(f, std::nothrow))
|
||||||
|
return 'SDK_';
|
||||||
|
|
||||||
|
if (ProDOSOrderDiskImage::Validate(f, std::nothrow))
|
||||||
|
return 'PO__';
|
||||||
|
|
||||||
|
if (DOSOrderDiskImage::Validate(f, std::nothrow))
|
||||||
|
return 'DO__';
|
||||||
|
|
||||||
|
return defv;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
unsigned BlockDevice::ImageType(const char *type, unsigned defv)
|
unsigned BlockDevice::ImageType(const char *type, unsigned defv)
|
||||||
{
|
{
|
||||||
|
@ -52,6 +77,8 @@ unsigned BlockDevice::ImageType(const char *type, unsigned defv)
|
||||||
if (::strcasecmp(type, "2img") == 0)
|
if (::strcasecmp(type, "2img") == 0)
|
||||||
return '2IMG';
|
return '2IMG';
|
||||||
|
|
||||||
|
if (::strcasecmp(type, "dc") == 0)
|
||||||
|
return 'DC42';
|
||||||
if (::strcasecmp(type, "dc42") == 0)
|
if (::strcasecmp(type, "dc42") == 0)
|
||||||
return 'DC42';
|
return 'DC42';
|
||||||
|
|
||||||
|
@ -74,6 +101,8 @@ unsigned BlockDevice::ImageType(const char *type, unsigned defv)
|
||||||
// not supported yet.
|
// not supported yet.
|
||||||
if (::strcasecmp(type, "sdk") == 0)
|
if (::strcasecmp(type, "sdk") == 0)
|
||||||
return 'SDK_';
|
return 'SDK_';
|
||||||
|
if (::strcasecmp(type, "shk") == 0)
|
||||||
|
return 'SDK_';
|
||||||
|
|
||||||
return defv;
|
return defv;
|
||||||
}
|
}
|
||||||
|
@ -92,22 +121,19 @@ BlockDevicePointer BlockDevice::Open(const char *name, File::FileFlags flags, un
|
||||||
throw POSIXException(__METHOD__ ": stat error", errno);
|
throw POSIXException(__METHOD__ ": stat error", errno);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!imageType)
|
// /dev/xxx ignore the type.
|
||||||
{
|
|
||||||
// /dev/xxxx
|
|
||||||
if (S_ISBLK(st.st_mode))
|
if (S_ISBLK(st.st_mode))
|
||||||
return RawDevice::Open(name, flags);
|
return RawDevice::Open(name, flags);
|
||||||
|
|
||||||
|
|
||||||
imageType = ImageType(name, 'PO__');
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO -- if no image type, guess based on file size?
|
|
||||||
|
|
||||||
MappedFile file(name, flags);
|
MappedFile file(name, flags);
|
||||||
|
|
||||||
|
|
||||||
|
if (!imageType)
|
||||||
|
{
|
||||||
|
imageType = ImageType(&file, 'PO__');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
switch (imageType)
|
switch (imageType)
|
||||||
{
|
{
|
||||||
case '2IMG':
|
case '2IMG':
|
||||||
|
@ -125,6 +151,10 @@ BlockDevicePointer BlockDevice::Open(const char *name, File::FileFlags flags, un
|
||||||
case 'DVX_':
|
case 'DVX_':
|
||||||
return DavexDiskImage::Open(&file);
|
return DavexDiskImage::Open(&file);
|
||||||
|
|
||||||
|
case 'SDK_':
|
||||||
|
return SDKImage::Open(name);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// throw an error?
|
// throw an error?
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
|
|
||||||
#include <File/File.h>
|
#include <File/File.h>
|
||||||
|
|
||||||
|
class MappedFile;
|
||||||
|
|
||||||
namespace Device {
|
namespace Device {
|
||||||
|
|
||||||
class BlockDevice : public ENABLE_SHARED_FROM_THIS(BlockDevice) {
|
class BlockDevice : public ENABLE_SHARED_FROM_THIS(BlockDevice) {
|
||||||
|
@ -20,6 +22,8 @@ public:
|
||||||
|
|
||||||
// static methods.
|
// static methods.
|
||||||
static unsigned ImageType(const char *type, unsigned defv = 0);
|
static unsigned ImageType(const char *type, unsigned defv = 0);
|
||||||
|
static unsigned ImageType(MappedFile *, unsigned defv = 0);
|
||||||
|
|
||||||
|
|
||||||
static BlockDevicePointer Open(const char *name, File::FileFlags flags, unsigned imageType = 0);
|
static BlockDevicePointer Open(const char *name, File::FileFlags flags, unsigned imageType = 0);
|
||||||
static BlockDevicePointer Create(const char *fname, const char *vname, unsigned blocks, unsigned imageType = 0);
|
static BlockDevicePointer Create(const char *fname, const char *vname, unsigned blocks, unsigned imageType = 0);
|
||||||
|
|
|
@ -47,42 +47,48 @@ DavexDiskImage::~DavexDiskImage()
|
||||||
// scan and update usedBlocks?
|
// scan and update usedBlocks?
|
||||||
}
|
}
|
||||||
|
|
||||||
void DavexDiskImage::Validate(MappedFile *f)
|
bool DavexDiskImage::Validate(MappedFile *f, const std::nothrow_t &)
|
||||||
{
|
{
|
||||||
#undef __METHOD__
|
#undef __METHOD__
|
||||||
#define __METHOD__ "DavexDiskImage::Validate"
|
#define __METHOD__ "DavexDiskImage::Validate"
|
||||||
|
|
||||||
size_t size = f->length();
|
size_t size = f->length();
|
||||||
const void * data = f->address();
|
const void * data = f->address();
|
||||||
bool ok = false;
|
|
||||||
unsigned blocks = (size / 512) - 1;
|
unsigned blocks = (size / 512) - 1;
|
||||||
|
|
||||||
do {
|
|
||||||
if (size < 512) break;
|
if (size < 512) return false;
|
||||||
if (size % 512) break;
|
if (size % 512) return false;
|
||||||
|
|
||||||
// identity.
|
// identity.
|
||||||
if (std::memcmp(data, IdentityCheck, 16))
|
if (std::memcmp(data, IdentityCheck, 16))
|
||||||
break;
|
return false;
|
||||||
|
|
||||||
// file format.
|
// file format.
|
||||||
if (Read8(data, 0x10) != 0)
|
if (Read8(data, 0x10) != 0)
|
||||||
break;
|
return false;
|
||||||
|
|
||||||
// total blocks
|
// total blocks
|
||||||
if (Read32(data, 33) != blocks)
|
if (Read32(data, 33) != blocks)
|
||||||
break;
|
return false;
|
||||||
|
|
||||||
// file number -- must be 1
|
// file number -- must be 1
|
||||||
if (Read8(data, 64) != 1)
|
if (Read8(data, 64) != 1)
|
||||||
break;
|
return false;
|
||||||
|
|
||||||
ok = true;
|
return true;
|
||||||
} while (false);
|
}
|
||||||
|
|
||||||
|
bool DavexDiskImage::Validate(MappedFile *f)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "DavexDiskImage::Validate"
|
||||||
|
|
||||||
|
|
||||||
if (!ok)
|
if (!Validate(f, std::nothrow))
|
||||||
throw Exception(__METHOD__ ": Invalid file format.");
|
throw Exception(__METHOD__ ": Invalid file format.");
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockDevicePointer DavexDiskImage::Open(MappedFile *file)
|
BlockDevicePointer DavexDiskImage::Open(MappedFile *file)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
#define __DAVEXDISKIMAGE_H__
|
#define __DAVEXDISKIMAGE_H__
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <new>
|
||||||
|
|
||||||
#include <Device/BlockDevice.h>
|
#include <Device/BlockDevice.h>
|
||||||
#include <Device/DiskImage.h>
|
#include <Device/DiskImage.h>
|
||||||
|
@ -22,12 +23,15 @@ public:
|
||||||
|
|
||||||
virtual BlockCachePointer createBlockCache();
|
virtual BlockCachePointer createBlockCache();
|
||||||
|
|
||||||
|
static bool Validate(MappedFile *, const std::nothrow_t &);
|
||||||
|
static bool Validate(MappedFile *);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
DavexDiskImage();
|
DavexDiskImage();
|
||||||
|
|
||||||
DavexDiskImage(MappedFile *);
|
DavexDiskImage(MappedFile *);
|
||||||
static void Validate(MappedFile *);
|
|
||||||
|
|
||||||
bool _changed;
|
bool _changed;
|
||||||
std::string _volumeName;
|
std::string _volumeName;
|
||||||
|
|
|
@ -170,42 +170,39 @@ BlockDevicePointer DiskCopy42Image::Create(const char *name, size_t blocks, cons
|
||||||
return MAKE_SHARED(DiskCopy42Image, file);
|
return MAKE_SHARED(DiskCopy42Image, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiskCopy42Image::Validate(MappedFile *file)
|
bool DiskCopy42Image::Validate(MappedFile *file, const std::nothrow_t &)
|
||||||
{
|
{
|
||||||
#undef __METHOD__
|
#undef __METHOD__
|
||||||
#define __METHOD__ "DiskCopy42Image::Validate"
|
#define __METHOD__ "DiskCopy42Image::Validate"
|
||||||
|
|
||||||
|
|
||||||
size_t bytes = 0;
|
size_t bytes = 0;
|
||||||
size_t size = file->length();
|
size_t size = file->length();
|
||||||
const void *data = file->address();
|
const void *data = file->address();
|
||||||
bool ok = false;
|
|
||||||
uint32_t checksum = 0;
|
uint32_t checksum = 0;
|
||||||
|
|
||||||
do {
|
if (size < oUserData)
|
||||||
if (size < oUserData) break;
|
return false;
|
||||||
|
|
||||||
// name must be < 64
|
// name must be < 64
|
||||||
if (Read8(data, 0) > 63) break;
|
if (Read8(data, 0) > 63)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (Read16(data, oPrivate) != 0x100)
|
if (Read16(data, oPrivate) != 0x100)
|
||||||
break;
|
return false;
|
||||||
|
|
||||||
// bytes, not blocks.
|
// bytes, not blocks.
|
||||||
bytes = Read32(data, oDataSize);
|
bytes = Read32(data, oDataSize);
|
||||||
|
|
||||||
if (bytes % 512) break;
|
if (bytes % 512)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (size < oUserData + bytes) break;
|
if (size < oUserData + bytes)
|
||||||
|
return false;
|
||||||
|
|
||||||
// todo -- checksum.
|
// todo -- checksum.
|
||||||
checksum = Read32(data, oDataChecksum);
|
checksum = Read32(data, oDataChecksum);
|
||||||
|
|
||||||
ok = true;
|
|
||||||
} while (false);
|
|
||||||
|
|
||||||
if (!ok)
|
|
||||||
throw Exception(__METHOD__ ": Invalid file format.");
|
|
||||||
|
|
||||||
uint32_t cs = Checksum(oUserData + (uint8_t *)data, bytes);
|
uint32_t cs = Checksum(oUserData + (uint8_t *)data, bytes);
|
||||||
|
|
||||||
if (cs != checksum)
|
if (cs != checksum)
|
||||||
|
@ -213,6 +210,20 @@ void DiskCopy42Image::Validate(MappedFile *file)
|
||||||
fprintf(stderr, __METHOD__ ": Warning: checksum invalid.\n");
|
fprintf(stderr, __METHOD__ ": Warning: checksum invalid.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool DiskCopy42Image::Validate(MappedFile *file)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "DiskCopy42Image::Validate"
|
||||||
|
|
||||||
|
|
||||||
|
if (!Validate(file, std::nothrow))
|
||||||
|
throw Exception(__METHOD__ ": Invalid file format.");
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiskCopy42Image::write(unsigned block, const void *bp)
|
void DiskCopy42Image::write(unsigned block, const void *bp)
|
||||||
|
|
|
@ -19,6 +19,11 @@ public:
|
||||||
|
|
||||||
static uint32_t Checksum(void *data, size_t size);
|
static uint32_t Checksum(void *data, size_t size);
|
||||||
|
|
||||||
|
static bool Validate(MappedFile *, const std::nothrow_t &);
|
||||||
|
static bool Validate(MappedFile *);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
virtual void write(unsigned block, const void *bp);
|
virtual void write(unsigned block, const void *bp);
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,7 +34,6 @@ private:
|
||||||
DiskCopy42Image();
|
DiskCopy42Image();
|
||||||
|
|
||||||
DiskCopy42Image(MappedFile *);
|
DiskCopy42Image(MappedFile *);
|
||||||
static void Validate(MappedFile *);
|
|
||||||
bool _changed;
|
bool _changed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -126,18 +126,33 @@ BlockDevicePointer ProDOSOrderDiskImage::Open(MappedFile *file)
|
||||||
return MAKE_SHARED(ProDOSOrderDiskImage, file);
|
return MAKE_SHARED(ProDOSOrderDiskImage, file);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProDOSOrderDiskImage::Validate(MappedFile *f)
|
|
||||||
|
bool ProDOSOrderDiskImage::Validate(MappedFile *f, const std::nothrow_t &)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "ProDOSOrderDiskImage::Validate"
|
||||||
|
|
||||||
|
|
||||||
|
size_t size = f->length();
|
||||||
|
|
||||||
|
if (size % 512)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ProDOSOrderDiskImage::Validate(MappedFile *f)
|
||||||
{
|
{
|
||||||
#undef __METHOD__
|
#undef __METHOD__
|
||||||
#define __METHOD__ "ProDOSOrderDiskImage::Validate"
|
#define __METHOD__ "ProDOSOrderDiskImage::Validate"
|
||||||
|
|
||||||
if (!f || !f->isValid()) throw Exception(__METHOD__ ": File not set.");
|
if (!f || !f->isValid()) throw Exception(__METHOD__ ": File not set.");
|
||||||
|
|
||||||
size_t size = f->length();
|
if (!Validate(f, std::nothrow))
|
||||||
|
|
||||||
if (size % 512)
|
|
||||||
throw Exception(__METHOD__ ": Invalid file format.");
|
throw Exception(__METHOD__ ": Invalid file format.");
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
BlockCachePointer ProDOSOrderDiskImage::createBlockCache()
|
BlockCachePointer ProDOSOrderDiskImage::createBlockCache()
|
||||||
|
@ -157,6 +172,8 @@ DOSOrderDiskImage::DOSOrderDiskImage(const char *name, bool readOnly) :
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DOSOrderDiskImage::DOSOrderDiskImage(MappedFile *file) :
|
DOSOrderDiskImage::DOSOrderDiskImage(MappedFile *file) :
|
||||||
DiskImage(file)
|
DiskImage(file)
|
||||||
{
|
{
|
||||||
|
@ -182,16 +199,30 @@ BlockDevicePointer DOSOrderDiskImage::Open(MappedFile *file)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DOSOrderDiskImage::Validate(MappedFile *f)
|
bool DOSOrderDiskImage::Validate(MappedFile *f, const std::nothrow_t &)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "DOSOrderDiskImage::Validate"
|
||||||
|
|
||||||
|
size_t size = f->length();
|
||||||
|
|
||||||
|
if (size % 512)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DOSOrderDiskImage::Validate(MappedFile *f)
|
||||||
{
|
{
|
||||||
#undef __METHOD__
|
#undef __METHOD__
|
||||||
#define __METHOD__ "DOSOrderDiskImage::Validate"
|
#define __METHOD__ "DOSOrderDiskImage::Validate"
|
||||||
|
|
||||||
if (!f || !f->isValid()) throw Exception(__METHOD__ ": File not set.");
|
if (!f || !f->isValid()) throw Exception(__METHOD__ ": File not set.");
|
||||||
|
|
||||||
size_t size = f->length();
|
|
||||||
|
|
||||||
if (size % 512)
|
if (!Validate(f, std::nothrow))
|
||||||
throw Exception(__METHOD__ ": Invalid file format.");
|
throw Exception(__METHOD__ ": Invalid file format.");
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,12 +63,13 @@ public:
|
||||||
|
|
||||||
virtual BlockCachePointer createBlockCache();
|
virtual BlockCachePointer createBlockCache();
|
||||||
|
|
||||||
|
static bool Validate(MappedFile *, const std::nothrow_t &);
|
||||||
|
static bool Validate(MappedFile *);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ProDOSOrderDiskImage();
|
ProDOSOrderDiskImage();
|
||||||
|
|
||||||
|
|
||||||
ProDOSOrderDiskImage(MappedFile *);
|
ProDOSOrderDiskImage(MappedFile *);
|
||||||
static void Validate(MappedFile *);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DOSOrderDiskImage : public DiskImage {
|
class DOSOrderDiskImage : public DiskImage {
|
||||||
|
@ -78,11 +79,13 @@ public:
|
||||||
static BlockDevicePointer Create(const char *name, size_t blocks);
|
static BlockDevicePointer Create(const char *name, size_t blocks);
|
||||||
static BlockDevicePointer Open(MappedFile *);
|
static BlockDevicePointer Open(MappedFile *);
|
||||||
|
|
||||||
|
static bool Validate(MappedFile *, const std::nothrow_t &);
|
||||||
|
static bool Validate(MappedFile *);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DOSOrderDiskImage();
|
DOSOrderDiskImage();
|
||||||
|
|
||||||
DOSOrderDiskImage(MappedFile *);
|
DOSOrderDiskImage(MappedFile *);
|
||||||
static void Validate(MappedFile *);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
249
Device/SDKImage.cpp
Normal file
249
Device/SDKImage.cpp
Normal file
|
@ -0,0 +1,249 @@
|
||||||
|
//
|
||||||
|
// SDKImage.cpp
|
||||||
|
// profuse
|
||||||
|
//
|
||||||
|
// Created by Kelvin Sherlock on 3/6/2011.
|
||||||
|
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "SDKImage.h"
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cerrno>
|
||||||
|
|
||||||
|
#include <NufxLib.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include <File/File.h>
|
||||||
|
#include <File/MappedFile.h>
|
||||||
|
|
||||||
|
#include <ProFUSE/Exception.h>
|
||||||
|
|
||||||
|
|
||||||
|
using ProFUSE::Exception;
|
||||||
|
using ProFUSE::POSIXException;
|
||||||
|
|
||||||
|
|
||||||
|
class NuFXException : public Exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
NuFXException(const char *cp, NuError error);
|
||||||
|
NuFXException(const std::string& string, NuError error);
|
||||||
|
|
||||||
|
virtual const char *errorString();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline NuFXException::NuFXException(const char *cp, NuError error) :
|
||||||
|
Exception(cp, error)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
inline NuFXException::NuFXException(const std::string& string, NuError error) :
|
||||||
|
Exception(string, error)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *NuFXException::errorString()
|
||||||
|
{
|
||||||
|
return ::NuStrError((NuError)error());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
using namespace Device;
|
||||||
|
|
||||||
|
struct record_thread
|
||||||
|
{
|
||||||
|
NuRecordIdx record_index;
|
||||||
|
NuThreadIdx thread_index;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static record_thread FindDiskImageThread(NuArchive *archive)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "SDKImage::FindThread"
|
||||||
|
|
||||||
|
record_thread rt;
|
||||||
|
NuError e;
|
||||||
|
NuAttr recordCount;
|
||||||
|
|
||||||
|
e = NuGetAttr(archive, kNuAttrNumRecords, &recordCount);
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
throw NuFXException(__METHOD__ ": NuGetAttr", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned position = 0; position < recordCount; ++position)
|
||||||
|
{
|
||||||
|
NuRecordIdx rIndex;
|
||||||
|
const NuRecord *record;
|
||||||
|
|
||||||
|
e = NuGetRecordIdxByPosition(archive, position, &rIndex);
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
throw NuFXException(__METHOD__ ": NuGetRecordIdxByPosition", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
e = NuGetRecord(archive, rIndex, &record);
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
throw NuFXException(__METHOD__ ": NuGetRecord", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < NuRecordGetNumThreads(record); ++i)
|
||||||
|
{
|
||||||
|
const NuThread *thread = NuGetThread(record, i);
|
||||||
|
|
||||||
|
if (NuGetThreadID(thread) == kNuThreadIDDiskImage)
|
||||||
|
{
|
||||||
|
rt.thread_index = thread->threadIdx;
|
||||||
|
rt.record_index = record->recordIdx;
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Exception(__METHOD__ ": not a disk image");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* helper function to extract SDK image to /tmp and return a
|
||||||
|
* ProDOSDiskImage of the /tmp file.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
BlockDevicePointer SDKImage::Open(const char *name)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "SDKImage::Open"
|
||||||
|
|
||||||
|
|
||||||
|
char tmp[] = "/tmp/pfuse.XXXXXXXX";
|
||||||
|
|
||||||
|
int fd = -1;
|
||||||
|
FILE *fp = NULL;
|
||||||
|
NuArchive *archive = NULL;
|
||||||
|
//const NuThread *thread = NULL;
|
||||||
|
//const NuRecord *record = NULL;
|
||||||
|
NuDataSink *sink = NULL;
|
||||||
|
//NuRecordIdx rIndex;
|
||||||
|
//NuThreadIdx tIndex;
|
||||||
|
|
||||||
|
NuError e;
|
||||||
|
|
||||||
|
|
||||||
|
record_thread rt = {0, 0};
|
||||||
|
|
||||||
|
try {
|
||||||
|
|
||||||
|
|
||||||
|
e = NuOpenRO(name, &archive);
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
throw NuFXException(__METHOD__ ": NuOpenRO", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
rt = FindDiskImageThread(archive);
|
||||||
|
|
||||||
|
fd = mkstemp(tmp);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
throw POSIXException(__METHOD__ ": mkstemp", errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
fp = fdopen(fd, "w");
|
||||||
|
if (!fp)
|
||||||
|
{
|
||||||
|
::close(fd);
|
||||||
|
throw POSIXException(__METHOD__ ": fdopen", errno);
|
||||||
|
}
|
||||||
|
|
||||||
|
e = NuCreateDataSinkForFP(true, kNuConvertOff, fp, &sink);
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
throw NuFXException(__METHOD__ ": NuCreateDataSinkForFP", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
e = NuExtractThread(archive, rt.thread_index, sink);
|
||||||
|
if (e)
|
||||||
|
{
|
||||||
|
throw NuFXException(__METHOD__ ": NuExtractThread", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "Extracted disk image to %s\n", tmp);
|
||||||
|
|
||||||
|
fclose(fp);
|
||||||
|
NuClose(archive);
|
||||||
|
NuFreeDataSink(sink);
|
||||||
|
fp = NULL;
|
||||||
|
archive = NULL;
|
||||||
|
sink = NULL;
|
||||||
|
}
|
||||||
|
catch(...)
|
||||||
|
{
|
||||||
|
if (fp) fclose(fp);
|
||||||
|
if (archive) NuClose(archive);
|
||||||
|
if (sink) NuFreeDataSink(sink);
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo -- maybe SDKImage should extend ProDOSOrderDiskImage, have destructor
|
||||||
|
// that unklinks the temp file.
|
||||||
|
|
||||||
|
MappedFile file(tmp, File::ReadOnly);
|
||||||
|
|
||||||
|
return ProDOSOrderDiskImage::Open(&file);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool SDKImage::Validate(MappedFile * f, const std::nothrow_t &)
|
||||||
|
{
|
||||||
|
|
||||||
|
// NuFile, alternating ASCII.
|
||||||
|
static const char IdentityCheck[6] = { 0x4E, 0xF5, 0x46, 0xE9, 0x6C, 0xE5 };
|
||||||
|
static const char BXYIdentityCheck[3] = { 0x0A, 0x47, 0x4C };
|
||||||
|
|
||||||
|
uint8_t *address = (uint8_t *)f->address();
|
||||||
|
size_t length = f->length();
|
||||||
|
|
||||||
|
// check for a BXY header
|
||||||
|
if (length >= 128
|
||||||
|
&& std::memcmp(address, BXYIdentityCheck, sizeof(BXYIdentityCheck)) == 0)
|
||||||
|
{
|
||||||
|
length -= 128;
|
||||||
|
address += 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (length > sizeof(IdentityCheck)
|
||||||
|
&& std::memcmp(address, IdentityCheck, sizeof(IdentityCheck)) == 0)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
|
||||||
|
return false;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SDKImage::Validate(MappedFile * f)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "SDKImage::Validate"
|
||||||
|
|
||||||
|
if (!Validate(f, std::nothrow))
|
||||||
|
throw Exception(__METHOD__ ": Invalid file format.");
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
30
Device/SDKImage.h
Normal file
30
Device/SDKImage.h
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// SDKImage.h
|
||||||
|
// profuse
|
||||||
|
//
|
||||||
|
// Created by Kelvin Sherlock on 3/6/2011.
|
||||||
|
// Copyright 2011 __MyCompanyName__. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include <Device/BlockDevice.h>
|
||||||
|
#include <Device/DiskImage.h>
|
||||||
|
|
||||||
|
namespace Device {
|
||||||
|
|
||||||
|
class SDKImage : public DiskImage
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
static BlockDevicePointer Open(const char *name);
|
||||||
|
|
||||||
|
|
||||||
|
static bool Validate(MappedFile *, const std::nothrow_t &);
|
||||||
|
static bool Validate(MappedFile *);
|
||||||
|
|
||||||
|
private:
|
||||||
|
SDKImage();
|
||||||
|
SDKImage(const SDKImage &);
|
||||||
|
~SDKImage();
|
||||||
|
SDKImage & operator=(const SDKImage &);
|
||||||
|
};
|
||||||
|
}
|
|
@ -100,42 +100,47 @@ BlockDevicePointer UniversalDiskImage::Open(MappedFile *file)
|
||||||
* TODO -- honor read-only flag.
|
* TODO -- honor read-only flag.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void UniversalDiskImage::Validate(MappedFile *file)
|
|
||||||
|
bool UniversalDiskImage::Validate(MappedFile *file, const std::nothrow_t &)
|
||||||
{
|
{
|
||||||
#undef __METHOD__
|
#undef __METHOD__
|
||||||
#define __METHOD__ "UniversalDiskImage::Validate"
|
#define __METHOD__ "UniversalDiskImage::Validate"
|
||||||
|
|
||||||
const void *data = file->address();
|
const void *data = file->address();
|
||||||
size_t size = file->length();
|
size_t size = file->length();
|
||||||
bool ok = false;
|
|
||||||
unsigned blocks = 0;
|
unsigned blocks = 0;
|
||||||
unsigned offset = 0;
|
unsigned offset = 0;
|
||||||
|
|
||||||
do {
|
|
||||||
|
|
||||||
if (size < 64) break;
|
if (size < 64) return false;
|
||||||
|
|
||||||
if (std::memcmp(data, "2IMG", 4)) break;
|
if (std::memcmp(data, "2IMG", 4)) return false;
|
||||||
|
|
||||||
// only prodos supported, for now...
|
// only prodos supported, for now...
|
||||||
// TODO -- Dos Order, Nibble support.
|
// TODO -- Dos Order, Nibble support.
|
||||||
if (Read32(data, 0x0c) != 1) break;
|
if (Read32(data, 0x0c) != 1) return false;
|
||||||
|
|
||||||
blocks = Read32(data, 0x14);
|
blocks = Read32(data, 0x14);
|
||||||
offset = Read32(data, 0x18);
|
offset = Read32(data, 0x18);
|
||||||
|
|
||||||
// file size == blocks * 512
|
// file size == blocks * 512
|
||||||
if (Read32(data, 0x1c) != blocks * 512) break;
|
if (Read32(data, 0x1c) != blocks * 512) return false;
|
||||||
|
|
||||||
if (offset + blocks * 512 > size) break;
|
if (offset + blocks * 512 > size) return false;
|
||||||
|
|
||||||
ok = true;
|
return true;
|
||||||
} while (false);
|
}
|
||||||
|
|
||||||
if (!ok)
|
bool UniversalDiskImage::Validate(MappedFile *file)
|
||||||
|
{
|
||||||
|
#undef __METHOD__
|
||||||
|
#define __METHOD__ "UniversalDiskImage::Validate"
|
||||||
|
|
||||||
|
if (!Validate(file, std::nothrow))
|
||||||
throw Exception(__METHOD__ ": Invalid file format.");
|
throw Exception(__METHOD__ ": Invalid file format.");
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,12 +22,15 @@ public:
|
||||||
virtual BlockCachePointer createBlockCache();
|
virtual BlockCachePointer createBlockCache();
|
||||||
|
|
||||||
|
|
||||||
|
static bool Validate(MappedFile *, const std::nothrow_t &);
|
||||||
|
static bool Validate(MappedFile *);
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
UniversalDiskImage();
|
UniversalDiskImage();
|
||||||
|
|
||||||
UniversalDiskImage(MappedFile *);
|
UniversalDiskImage(MappedFile *);
|
||||||
static void Validate(MappedFile *);
|
|
||||||
|
|
||||||
uint32_t _format;
|
uint32_t _format;
|
||||||
uint32_t _flags;
|
uint32_t _flags;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user