git-svn-id: https://profuse.googlecode.com/svn/branches/v2@115 aa027e90-d47c-11dd-86d7-074df07e0730

This commit is contained in:
ksherlock 2009-11-26 15:58:10 +00:00
parent 1ba3d83ec7
commit ee7736d7b8
7 changed files with 353 additions and 37 deletions

View File

@ -9,6 +9,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <cstdio>
#include <algorithm>
using namespace ProFUSE;
using namespace LittleEndian;
@ -89,6 +90,10 @@ DavexDiskImage *DavexDiskImage::Open(MappedFile *file)
}
DavexDiskImage *DavexDiskImage::Create(const char *name, size_t blocks)
{
return Create(name, blocks, "Untitled");
}
DavexDiskImage *DavexDiskImage::Create(const char *name, size_t blocks, const char *vname)
{
#undef __METHOD__
#define __METHOD__ "DavexDiskImage::Create"
@ -122,7 +127,10 @@ DavexDiskImage *DavexDiskImage::Create(const char *name, size_t blocks)
header.push32le(0);
// volume Name
header.pushBytes("\x08Untitled", 9);
if (!vname || !*vname) vname = "Untitled";
unsigned l = std::strlen(vname);
header.push8(std::min(l, 15u));
header.pushBytes(vname, std::min(l, 15u));
// name + reserved.
header.resize(64);

View File

@ -14,6 +14,7 @@ public:
virtual ~DavexDiskImage();
static DavexDiskImage *Create(const char *name, size_t blocks);
static DavexDiskImage *Create(const char *name, size_t blocks, const char *vname);
static DavexDiskImage *Open(MappedFile *);

View File

@ -4,6 +4,8 @@
#include "Endian.h"
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace ProFUSE;
using namespace BigEndian;
@ -85,6 +87,11 @@ static uint8_t FormatByte(size_t blocks)
}
}
DiskCopy42Image *DiskCopy42Image::Create(const char *name, size_t blocks)
{
return Create(name, blocks, "Untitled");
}
DiskCopy42Image *DiskCopy42Image::Create(const char *name, size_t blocks, const char *vname)
{
MappedFile *file = new MappedFile(name, blocks * 512 + 84);
file->setOffset(84);
@ -92,8 +99,13 @@ DiskCopy42Image *DiskCopy42Image::Create(const char *name, size_t blocks)
Buffer header(84);
// name -- 64byte pstring.
header.pushBytes("\x08Untitled", 9);
// name -- 64byte pstring.
if (vname == NULL) vname = "Untitled";
unsigned l = std::strlen(vname);
header.push8(std::min(l, 63u));
header.pushBytes(vname, std::min(l, 63u));
header.resize(64);
// data size -- number of bytes
@ -139,11 +151,14 @@ DiskCopy42Image *DiskCopy42Image::Create(const char *name, size_t blocks)
void DiskCopy42Image::Validate(MappedFile *file)
{
#undef __METHOD__
#define __METHOD__ "DiskCopy42Image::Validate"
size_t bytes = 0;
size_t size = file->fileSize();
const void *data = file->fileData();
bool ok = false;
uint32_t checksum;
uint32_t checksum = 0;
do {
if (size < 84) break;
@ -167,6 +182,8 @@ void DiskCopy42Image::Validate(MappedFile *file)
ok = true;
} while (false);
if (!ok)
throw Exception(__METHOD__ ": Invalid file format.");
uint32_t cs = Checksum(64 + (uint8_t *)data, bytes);

View File

@ -13,6 +13,8 @@ public:
virtual ~DiskCopy42Image();
static DiskCopy42Image *Create(const char *name, size_t blocks);
static DiskCopy42Image *Create(const char *name, size_t blocks, const char *vname);
static DiskCopy42Image *Open(MappedFile *);
static uint32_t Checksum(void *data, size_t size);

View File

@ -8,68 +8,68 @@
namespace LittleEndian {
uint8_t Read8(const void *vp)
inline uint8_t Read8(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return (p[0]);
}
uint16_t Read16(const void *vp)
inline uint16_t Read16(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return p[0] | (p[1] << 8);
}
uint32_t Read24(const void *vp)
inline uint32_t Read24(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return (p[0]) | (p[1] << 8) | (p[2] << 16);
}
uint32_t Read32(const void *vp)
inline uint32_t Read32(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return (p[0]) | (p[1] << 8) | (p[2] << 16) | (p[3] << 24);
}
uint8_t Read8(const void *vp, unsigned offset)
inline uint8_t Read8(const void *vp, unsigned offset)
{
return Read8(offset + (const uint8_t *)vp);
}
uint16_t Read16(const void *vp, unsigned offset)
inline uint16_t Read16(const void *vp, unsigned offset)
{
return Read16(offset + (const uint8_t *)vp);
}
uint32_t Read24(const void *vp, unsigned offset)
inline uint32_t Read24(const void *vp, unsigned offset)
{
return Read24(offset + (const uint8_t *)vp);
}
uint32_t Read32(const void *vp, unsigned offset)
inline uint32_t Read32(const void *vp, unsigned offset)
{
return Read32(offset + (const uint8_t *)vp);
}
// write
void Write8(void *vp, uint8_t x)
inline void Write8(void *vp, uint8_t x)
{
uint8_t *p = (uint8_t *)vp;
p[0] = x;
}
void Write16(void *vp, uint16_t x)
inline void Write16(void *vp, uint16_t x)
{
uint8_t *p = (uint8_t *)vp;
p[0] = (x) & 0xff;
p[1] = (x >> 8) & 0xff;
}
void Write24(void *vp, uint32_t x)
inline void Write24(void *vp, uint32_t x)
{
uint8_t *p = (uint8_t *)vp;
p[0] = (x) & 0xff;
@ -77,7 +77,7 @@ namespace LittleEndian {
p[2] = (x >> 16) & 0xff;
}
void Write32(void *vp, uint32_t x)
inline void Write32(void *vp, uint32_t x)
{
uint8_t *p = (uint8_t *)vp;
p[0] = (x) & 0xff;
@ -86,22 +86,22 @@ namespace LittleEndian {
p[3] = (x >> 24) & 0xff;
}
void Write8(void *vp, unsigned offset, uint8_t x)
inline void Write8(void *vp, unsigned offset, uint8_t x)
{
Write8(offset + (uint8_t *)vp, x);
}
void Write16(void *vp, unsigned offset, uint16_t x)
inline void Write16(void *vp, unsigned offset, uint16_t x)
{
Write16(offset + (uint8_t *)vp, x);
}
void Write24(void *vp, unsigned offset, uint32_t x)
inline void Write24(void *vp, unsigned offset, uint32_t x)
{
Write24(offset + (uint8_t *)vp, x);
}
void Write32(void *vp, unsigned offset, uint32_t x)
inline void Write32(void *vp, unsigned offset, uint32_t x)
{
Write32(offset + (uint8_t *)vp, x);
}
@ -112,48 +112,48 @@ namespace LittleEndian {
namespace BigEndian {
uint8_t Read8(const void *vp)
inline uint8_t Read8(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return p[0];
}
uint16_t Read16(const void *vp)
inline uint16_t Read16(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return (p[0] << 8) | (p[1]);
}
uint32_t Read24(const void *vp)
inline uint32_t Read24(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return (p[0] << 16) | (p[1] << 8) | (p[2]);
}
uint32_t Read32(const void *vp)
inline uint32_t Read32(const void *vp)
{
const uint8_t *p = (const uint8_t *)vp;
return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | (p[3]);
}
uint8_t Read8(const void *vp, unsigned offset)
inline uint8_t Read8(const void *vp, unsigned offset)
{
return Read8(offset + (const uint8_t *)vp);
}
uint16_t Read16(const void *vp, unsigned offset)
inline uint16_t Read16(const void *vp, unsigned offset)
{
return Read16(offset + (const uint8_t *)vp);
}
uint32_t Read24(const void *vp, unsigned offset)
inline uint32_t Read24(const void *vp, unsigned offset)
{
return Read24(offset + (const uint8_t *)vp);
}
uint32_t Read32(const void *vp, unsigned offset)
inline uint32_t Read32(const void *vp, unsigned offset)
{
return Read32(offset + (const uint8_t *)vp);
}
@ -161,20 +161,20 @@ namespace BigEndian {
// write
void Write8(void *vp, uint8_t x)
inline void Write8(void *vp, uint8_t x)
{
uint8_t *p = (uint8_t *)vp;
p[0] = x;
}
void Write16(void *vp, uint16_t x)
inline void Write16(void *vp, uint16_t x)
{
uint8_t *p = (uint8_t *)vp;
p[0] = (x >> 8) & 0xff;
p[1] = (x) & 0xff;
}
void Write24(void *vp, uint32_t x)
inline void Write24(void *vp, uint32_t x)
{
uint8_t *p = (uint8_t *)vp;
p[0] = (x >> 16) & 0xff;
@ -182,7 +182,7 @@ namespace BigEndian {
p[2] = (x) & 0xff;
}
void Write32(void *vp, uint32_t x)
inline void Write32(void *vp, uint32_t x)
{
uint8_t *p = (uint8_t *)vp;
p[0] = (x >> 24) & 0xff;
@ -191,22 +191,22 @@ namespace BigEndian {
p[3] = (x) & 0xff;
}
void Write8(void *vp, unsigned offset, uint8_t x)
inline void Write8(void *vp, unsigned offset, uint8_t x)
{
Write8(offset + (uint8_t *)vp, x);
}
void Write16(void *vp, unsigned offset, uint16_t x)
inline void Write16(void *vp, unsigned offset, uint16_t x)
{
Write16(offset + (uint8_t *)vp, x);
}
void Write24(void *vp, unsigned offset, uint32_t x)
inline void Write24(void *vp, unsigned offset, uint32_t x)
{
Write24(offset + (uint8_t *)vp, x);
}
void Write32(void *vp, unsigned offset, uint32_t x)
inline void Write32(void *vp, unsigned offset, uint32_t x)
{
Write32(offset + (uint8_t *)vp, x);
}

View File

@ -80,7 +80,7 @@ UniversalDiskImage *UniversalDiskImage::Open(MappedFile *file)
void UniversalDiskImage::Validate(MappedFile *file)
{
#undef __METHOD__
#define __METHOD__ "DavexDiskImage::Validate"
#define __METHOD__ "UniversalDiskImage::Validate"
const void *data = file->fileData();
size_t size = file->fileSize();

288
newfs_prodos.cpp Normal file
View File

@ -0,0 +1,288 @@
#include "BlockDevice.h"
#include "UniversalDiskImage.h"
#include "DiskCopy42Image.h"
#include "DavexDiskImage.h"
#include "RawDevice.h"
#include "Exception.h"
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cerrno>
#include <memory>
#include <unistd.h>
#define NEWFS_VERSION "0.1"
using namespace ProFUSE;
void usage()
{
std::printf("newfs_prodos %s\n", NEWFS_VERSION);
std::printf("\n");
std::printf("newfs_prodos [-v volume_name] [-s size] [-f format] file\n");
std::printf("\n");
std::printf(" -v volume_name specify the volume name.\n"
" Default is Untitled.\n"
" -s size specify size in blocks.\n"
" Default is 1600 blocks (800K)\n"
" -f format specify the disk image format. Valid values are:\n"
" 2mg Universal Disk Image (default)\n"
" dc42 DiskCopy 4.2 Image\n"
" po ProDOS Order Disk Image\n"
" do DOS Order Disk Image\n"
" davex Davex Disk Image\n"
);
}
/*
* \d+ by block
* \d+[Kk] by kilobyte
* \d+[Mm] by megabyte
*/
unsigned parseBlocks(const char *cp)
{
unsigned long blocks = 0;
char *mod;
errno = 0;
blocks = std::strtoul(cp, &mod, 10);
if (errno) return -1;
if (mod == cp) return -1;
if (blocks > 0xffff) return -1;
if (mod)
{
switch(*mod)
{
case 0:
break;
case 'm': // 1m = 1024*1024b = 2048 blocks
case 'M':
blocks *= 2048;
break;
case 'k': // 1k = 1024b = 2 blocks
case 'K':
blocks *= 2;
break;
}
if (blocks > 0xffff) return -1;
}
return (unsigned)blocks;
}
unsigned parseFormat(const char *type, unsigned defv = 0)
{
if (type == 0 || *type == 0) return defv;
if (::strcasecmp(type, "2mg") == 0)
return '2IMG';
if (::strcasecmp(type, "2img") == 0)
return '2IMG';
if (::strcasecmp(type, "dc42") == 0)
return 'DC42';
if (::strcasecmp(type, "po") == 0)
return 'PO__';
if (::strcasecmp(type, "do") == 0)
return 'DO__';
if (::strcasecmp(type, "davex") == 0)
return 'DVX_';
return defv;
}
// return the filename extension, NULL if none.
const char *extname(const char *src)
{
if (!src) return NULL;
unsigned l = std::strlen(src);
for (unsigned i = 0; i < l; ++i)
{
char c = src[l - 1 - i];
if (c == '/') return NULL;
if (c == '.') return src + l - i;
}
return NULL;
}
// return the basename, without an extension.
std::string filename(const std::string& src)
{
unsigned start;
unsigned end;
if (src.empty()) return std::string("");
start = end = 0;
for(unsigned i = 0, l = src.length(); i < l; ++i)
{
char c = src[i];
if (c == '/') start = end = i + 1;
if (c == '.') end = i;
}
if (start == src.length()) return std::string("");
if (start == end) return src.substr(start);
return src.substr(start, end - start);
}
bool ValidName(const char *cp)
{
unsigned i = 0;
if (!cp || !*cp) return false;
if (!isalpha(*cp)) return false;
for (i = 1; i <17; ++i)
{
unsigned char c = cp[i];
if (c == 0) break;
if (c == '.') continue;
if (isalnum(c)) continue;
return false;
}
return i < 16;
}
int main(int argc, char **argv)
{
unsigned blocks = 1600;
std::string volumeName;
std::string fileName;
int format = 0;
const char *fname;
int c;
// ctype uses ascii only.
::setlocale(LC_ALL, "C");
while ( (c = ::getopt(argc, argv, "hf:s:v:")) != -1)
{
switch(c)
{
case '?':
case 'h':
usage();
return 0;
break;
case 'v':
volumeName = optarg;
// make sure it's legal.
if (!ValidName(optarg))
{
std::fprintf(stderr, "Error: `%s' is not a valid ProDOS volume name.\n", optarg);
return 0x40;
}
break;
case 's':
blocks = parseBlocks(optarg);
if (blocks > 0xffff)
{
std::fprintf(stderr, "Error: `%s' is not a valid disk size.\n", optarg);
return 0x5a;
}
break;
case 'f':
{
format = parseFormat(optarg);
if (format == 0)
{
std::fprintf(stderr, "Error: `%s' is not a supposed disk image format.\n", optarg);
return -1;
}
}
}
}
argc -= optind;
argv += optind;
if (argc != 1)
{
usage();
return -1;
}
fname = argv[0];
fileName = argv[0];
// generate a filename.
if (volumeName.empty())
{
volumeName = filename(fileName);
if (volumeName.empty() || !ValidName(volumeName.c_str()))
volumeName = "Untitled";
}
if (format == 0) format = parseFormat(extname(fname));
try
{
std::auto_ptr<BlockDevice> device;
//auto_ptr<VolumeDirectory> volume;
// todo -- check if path matches /dev/xxx; if so, use RawDevice.
// todo -- check if file exists at path?
switch(format)
{
case 'DC42':
// todo -- pass in volume name
device.reset(DiskCopy42Image::Create(fname, blocks, volumeName.c_str()));
break;
case 'PO__':
device.reset(ProDOSOrderDiskImage::Create(fname, blocks));
break;
case 'DO__':
device.reset(DOSOrderDiskImage::Create(fname, blocks));
break;
case 'DVX_':
device.reset(DavexDiskImage::Create(fname, blocks, volumeName.c_str()));
break;
case '2IMG':
default:
device.reset(UniversalDiskImage::Create(fname, blocks));
}
// VolumeDirectory assumes ownership of device,
// but doesn't release it on exception.
//volume.reset(new VolumeDirectory(name, device));
device.release();
}
catch (Exception e)
{
std::fprintf(stderr, "Error: %s\n", e.what());
return -1;
}
return 0;
}