mirror of
https://github.com/ksherlock/profuse.git
synced 2024-12-25 08:29:22 +00:00
git-svn-id: https://profuse.googlecode.com/svn/branches/v2@134 aa027e90-d47c-11dd-86d7-074df07e0730
This commit is contained in:
parent
b8d728c781
commit
2675797136
29
pascal/DateRec.cpp
Normal file
29
pascal/DateRec.cpp
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#include "DateRec.h"
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
|
using namespace Pascal;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DateRec::DateRec(unsigned val)
|
||||||
|
{
|
||||||
|
// yyyy yyym mmmm dddd
|
||||||
|
_day = val & 0xf;
|
||||||
|
_month = (val >> 4) & 0x1f;
|
||||||
|
_year = (val >> 9) & 0x7f;
|
||||||
|
}
|
||||||
|
|
||||||
|
DateRec::operator std::time_t() const {
|
||||||
|
struct tm tm;
|
||||||
|
|
||||||
|
if (_day == 0 || _month == 0) return (std::time_t)-1;
|
||||||
|
|
||||||
|
std::memset(&tm, 0, sizeof(tm));
|
||||||
|
tm.tm_hour = 12;
|
||||||
|
tm.tm_mday = _day;
|
||||||
|
tm.tm_mon = _month;
|
||||||
|
tm.tm_year = _year;
|
||||||
|
tm.tm_isdst = -1;
|
||||||
|
|
||||||
|
return std::mktime(&tm);
|
||||||
|
}
|
44
pascal/DateRec.h
Normal file
44
pascal/DateRec.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#ifndef __DATEREC_H__
|
||||||
|
#define __DATEREC_H__
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
|
||||||
|
namespace Pascal {
|
||||||
|
|
||||||
|
class DateRec {
|
||||||
|
public:
|
||||||
|
|
||||||
|
DateRec();
|
||||||
|
DateRec(unsigned yy, unsigned mm, unsigned dd);
|
||||||
|
DateRec(unsigned);
|
||||||
|
|
||||||
|
operator std::time_t() const;
|
||||||
|
|
||||||
|
unsigned month() const { return _month; }
|
||||||
|
unsigned day() const { return _day; }
|
||||||
|
unsigned year() const { return _year; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned _year;
|
||||||
|
unsigned _month;
|
||||||
|
unsigned _day;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
inline DateRec::DateRec()
|
||||||
|
{
|
||||||
|
_year = 0;
|
||||||
|
_month = 0;
|
||||||
|
_day = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline DateRec::DateRec(unsigned yy, unsigned mm, unsigned dd)
|
||||||
|
{
|
||||||
|
_year = yy;
|
||||||
|
_month = mm;
|
||||||
|
_day = dd;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
359
pascal/File.cpp
Normal file
359
pascal/File.cpp
Normal file
@ -0,0 +1,359 @@
|
|||||||
|
#include "File.h"
|
||||||
|
#include "../auto.h"
|
||||||
|
#include "../Endian.h"
|
||||||
|
#include "../BlockDevice.h"
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory.h>
|
||||||
|
|
||||||
|
using namespace LittleEndian;
|
||||||
|
using namespace Pascal;
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark DirEntry
|
||||||
|
|
||||||
|
Entry::Entry()
|
||||||
|
{
|
||||||
|
_firstBlock = 0;
|
||||||
|
_lastBlock = 0;
|
||||||
|
_fileKind = 0;
|
||||||
|
_inode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry::Entry(void *vp)
|
||||||
|
{
|
||||||
|
init(vp);
|
||||||
|
}
|
||||||
|
|
||||||
|
Entry::~Entry()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Entry::init(void *vp)
|
||||||
|
{
|
||||||
|
_firstBlock = Read16(vp, 0x00);
|
||||||
|
_lastBlock = Read16(vp, 0x02);
|
||||||
|
_fileKind = Read8(vp, 0x04);
|
||||||
|
|
||||||
|
_inode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark VolumeEntry
|
||||||
|
|
||||||
|
VolumeEntry::VolumeEntry()
|
||||||
|
{
|
||||||
|
_fileNameLength = 0;
|
||||||
|
std::memset(_fileName, 0, 8);
|
||||||
|
_lastVolumeBlock = 0;
|
||||||
|
_numberOfFiles = 0;
|
||||||
|
_accessTime = 0;
|
||||||
|
|
||||||
|
setInode(1);
|
||||||
|
_inodeGenerator = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
VolumeEntry::VolumeEntry(ProFUSE::BlockDevice *device)
|
||||||
|
{
|
||||||
|
auto_array<uint8_t> buffer(new uint8_t[512]);
|
||||||
|
unsigned blockCount;
|
||||||
|
|
||||||
|
// read the header block, then load up all the header
|
||||||
|
// blocks.
|
||||||
|
|
||||||
|
device->read(2, buffer.get());
|
||||||
|
|
||||||
|
init(tmp);
|
||||||
|
|
||||||
|
// todo -- verify reasonable values.
|
||||||
|
blockCount = blocks();
|
||||||
|
if (blockCount > 1)
|
||||||
|
{
|
||||||
|
buffer.reset(new uint8_t[512 * blockCount]);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < blockCount; ++i)
|
||||||
|
{
|
||||||
|
device->read(2 + i, buffer.get() + 512 * i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now load up all the children.
|
||||||
|
// if this throws, memory could be lost...
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
for (unsigned i = 1; i < _numberFiles; ++i)
|
||||||
|
{
|
||||||
|
std::auto_ptr<FileEntry> child;
|
||||||
|
|
||||||
|
child.reset(new FileEntry(buffer.get() + i * 0x1a));
|
||||||
|
|
||||||
|
child->setInode(++_inodeGenerator);
|
||||||
|
_files.push_back(child.release());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
std::vector<FileEntry *>iterator iter;
|
||||||
|
for(iter = _files.begin(); iter != _files.end(); ++iter)
|
||||||
|
{
|
||||||
|
if (*iter) delete *iter;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
VolumeEntry::~VolumeEntry()
|
||||||
|
{
|
||||||
|
std::vector<FileEntry *>iterator iter;
|
||||||
|
for(iter = _files.begin(); iter != _files.end(); ++iter)
|
||||||
|
{
|
||||||
|
if (*iter) delete *iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void VolumeEntry::init(void *vp)
|
||||||
|
{
|
||||||
|
Entry::init(vp);
|
||||||
|
_fileNameLength = Read8(vp, 6);
|
||||||
|
|
||||||
|
// verify filenamelength <= 7
|
||||||
|
// verify fileKind == 0
|
||||||
|
|
||||||
|
std::memcpy(_fileName, 7 + (uint8_t *)vp, _fileNameLength);
|
||||||
|
|
||||||
|
_lastVolumeBlock = Read16(vp, 0x0e);
|
||||||
|
_numberFile = Read16(vp, 0x10);
|
||||||
|
_accessTime = Read16(vp, 0x12);
|
||||||
|
_bootDate = DateRec(Read16(vp, 0x14);
|
||||||
|
|
||||||
|
setInode(1);
|
||||||
|
_inodeGenerator = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
FileEntry *VolumeEntry::fileAtIndex(unsigned i) const
|
||||||
|
{
|
||||||
|
return i < _files.length() ? _files[i] : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#pragma mark -
|
||||||
|
#pragma mark FileEntry
|
||||||
|
|
||||||
|
FileEntry::FileEntry(void *vp) :
|
||||||
|
Entry(vp)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned File::fileSize() {
|
||||||
|
return (_lastBlock - _firstBlock - 1) * 512 + _lastByte;
|
||||||
|
}
|
||||||
|
|
||||||
|
int File::read(uint8_t *buffer, unsigned size, unsigned offset)
|
||||||
|
{
|
||||||
|
uint8_t tmp[512];
|
||||||
|
|
||||||
|
unsigned fileSize = fileSize();
|
||||||
|
unsigned count = 0;
|
||||||
|
unsigned block = 0;
|
||||||
|
|
||||||
|
if (offset >= fileSize) return 0;
|
||||||
|
|
||||||
|
if (offset + size > fileSize) size = fileSize - offset;
|
||||||
|
|
||||||
|
block = _startBlock + (offset / 512);
|
||||||
|
|
||||||
|
// returned value (count) is equal to size at this point.
|
||||||
|
// (no partial reads).
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 1. Block align everything
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (offset % 512)
|
||||||
|
{
|
||||||
|
unsigned bytes = std::min(offset % 512, size);
|
||||||
|
|
||||||
|
_device->read(block++, tmp);
|
||||||
|
|
||||||
|
std::memcpy(buffer, tmp + 512 - bytes, bytes);
|
||||||
|
|
||||||
|
buffer += bytes;
|
||||||
|
count += bytes;
|
||||||
|
size -= bytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 2. read full blocks into the buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
while (size >= 512)
|
||||||
|
{
|
||||||
|
_device->read(block++, buffer);
|
||||||
|
|
||||||
|
buffer += 512;
|
||||||
|
count += 512;
|
||||||
|
size -= 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 3. Read any trailing blocks.
|
||||||
|
*/
|
||||||
|
if (size)
|
||||||
|
{
|
||||||
|
_device->read(block, tmp);
|
||||||
|
std::memcpy(buffer, tmp, size);
|
||||||
|
|
||||||
|
count += size;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int TextFile::read(uint8_t *buffer, unsigned size, unsigned offset)
|
||||||
|
{
|
||||||
|
unsigned page = 0;
|
||||||
|
unsigned to = 0;
|
||||||
|
unsigned l = _pageSize.length();
|
||||||
|
unsigned block;
|
||||||
|
unsigned count = 0;
|
||||||
|
|
||||||
|
auto_array<uint8_t> tmp;
|
||||||
|
unsigned tmpSize = 0;
|
||||||
|
|
||||||
|
if (offset >= _fileSize) return 0;
|
||||||
|
if (offset + size > _fileSize) size = _fileSize - offset;
|
||||||
|
|
||||||
|
|
||||||
|
// find the first page.
|
||||||
|
for (page = 1; page < l; ++page)
|
||||||
|
{
|
||||||
|
if (to + _pageSize[page] > offset)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
to += _pageSize[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
--page;
|
||||||
|
|
||||||
|
block = _startBlock + 2 + (page * 2);
|
||||||
|
|
||||||
|
|
||||||
|
// offset not needed anymore,
|
||||||
|
// convert to offset from *this* page.
|
||||||
|
offset -= to;
|
||||||
|
|
||||||
|
while (size)
|
||||||
|
{
|
||||||
|
unsigned pageSize = _pageSize[page];
|
||||||
|
if (pageSize > tmp)
|
||||||
|
{
|
||||||
|
tmp.reset(new uint8_t[pageSize]);
|
||||||
|
tmpSize = pageSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes = std::min(size, pageSize - offset);
|
||||||
|
|
||||||
|
decodePage(block, tmp.get());
|
||||||
|
|
||||||
|
|
||||||
|
std::memcpy(buffer, tmp.get() + offset, bytes);
|
||||||
|
|
||||||
|
|
||||||
|
block += 2;
|
||||||
|
page += 1;
|
||||||
|
|
||||||
|
size -= bytes;
|
||||||
|
buffer += bytes;
|
||||||
|
count += bytes;
|
||||||
|
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
unsigned TextFile::decodePage(unsigned block, uint8_t *out)
|
||||||
|
{
|
||||||
|
uint8_t buffer[1024];
|
||||||
|
unsigned size = 0;
|
||||||
|
unsigned bytes = readPage(block, buffer);
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < bytes; ++i)
|
||||||
|
{
|
||||||
|
uint8_t c = buffer[i];
|
||||||
|
|
||||||
|
if (!c) break;
|
||||||
|
if (c == 16 && i != bytes - 1)
|
||||||
|
{
|
||||||
|
// DLE
|
||||||
|
// 16, n -> n-32 spaces.
|
||||||
|
unsigned x = buffer[++i] - 32;
|
||||||
|
|
||||||
|
if (out) for(unsigned i = 0; i < x; ++i) *out++ = ' ';
|
||||||
|
size += x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (out) *out++ = c;
|
||||||
|
size += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned TextFile::readPage(unsigned block, uint8_t *in)
|
||||||
|
{
|
||||||
|
// reads up to 2 blocks.
|
||||||
|
// assumes block within _startBlock ... _endBlock - 1
|
||||||
|
unsigned size = 0;
|
||||||
|
|
||||||
|
_device->read(block, in);
|
||||||
|
if (block + 1 == _endBlock)
|
||||||
|
{
|
||||||
|
return _lastByte;
|
||||||
|
}
|
||||||
|
|
||||||
|
_device->read(block + 1, in + 512);
|
||||||
|
if (block +2 == _endBlock)
|
||||||
|
{
|
||||||
|
return 512 + _lastByte;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1024;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void TextFile::init()
|
||||||
|
{
|
||||||
|
// calculate the file size and page offsets.
|
||||||
|
|
||||||
|
_pageSize.reserve((_endBlock - _startBlock - 2) / 2);
|
||||||
|
|
||||||
|
_fileSize = 0;
|
||||||
|
for (unsigned block = _startBlock + 2; block < _endBlock; block += 2)
|
||||||
|
{
|
||||||
|
unsigned size = decodePage(block, NULL);
|
||||||
|
_fileSize += size;
|
||||||
|
_pageSize.push_back(size);
|
||||||
|
}
|
||||||
|
}
|
111
pascal/File.h
Normal file
111
pascal/File.h
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
#ifndef __FILE_H__
|
||||||
|
#define __FILE_H__
|
||||||
|
|
||||||
|
#include "DateRec.h"
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace ProFUSE {
|
||||||
|
class BlockDevice;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Pascal {
|
||||||
|
|
||||||
|
class FileEntry;
|
||||||
|
|
||||||
|
class Entry {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
virtual ~Entry();
|
||||||
|
|
||||||
|
unsigned firstBlock() const { return _firstBlock; }
|
||||||
|
unsigned lastBlock() const { return _lastBlock; }
|
||||||
|
unsigned blocks() const { return _firstBlock - lastBlock; }
|
||||||
|
|
||||||
|
unsigned fileKind() const { return _fileKind; }
|
||||||
|
|
||||||
|
unsigned inode() const { return _inode; }
|
||||||
|
void setInode(unsigned inode) { _inode = inode; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
Entry();
|
||||||
|
Entry(void *);
|
||||||
|
void init(void *);
|
||||||
|
|
||||||
|
unsigned _firstBlock;
|
||||||
|
unsigned _lastBlock;
|
||||||
|
unsigned _fileKind;
|
||||||
|
|
||||||
|
unsigned _inode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class VolumeEntry : public Entry {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
VolumeEntry(ProFUSE::BlockDevice *);
|
||||||
|
virtual ~VolumeEntry();
|
||||||
|
|
||||||
|
const char *name() const { return _fileName; }
|
||||||
|
unsigned fileCount() const { return _numberFiles; }
|
||||||
|
|
||||||
|
Pascal::DateRec lastBoot() const { return _lastBoot; }
|
||||||
|
|
||||||
|
FileEntry *fileAtIndex(unsigned i) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
unsigned _fileNameLength;
|
||||||
|
char _fileName[8];
|
||||||
|
unsigned _lastVolumeBlock;
|
||||||
|
unsigned _numberFiles;
|
||||||
|
unsigned _accessTime;
|
||||||
|
Pascal::DateRec _lastBoot;
|
||||||
|
|
||||||
|
std::vector<FileEntry *> _files;
|
||||||
|
unsigned _inodeGenerator;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class FileEntry : public Entry {
|
||||||
|
public:
|
||||||
|
|
||||||
|
FileEntry(void *vp);
|
||||||
|
virtual ~FileEntry();
|
||||||
|
|
||||||
|
unsigned fileSize();
|
||||||
|
int read(uint8_t *buffer, unsigned size, unsigned offset);
|
||||||
|
|
||||||
|
const char *name() const { return _fileName; }
|
||||||
|
DateRec modification() const { return _modification; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
unsigned _status;
|
||||||
|
|
||||||
|
unsigned _fileNameLength;
|
||||||
|
char _fileName[16];
|
||||||
|
|
||||||
|
unsigned _lastByte;
|
||||||
|
DateRec _modification;
|
||||||
|
|
||||||
|
// for text files.
|
||||||
|
|
||||||
|
unsigned readTextPage(unsigned block, uint8_t *in);
|
||||||
|
unsigned decodeTextPage(unsigned block, uint8_t *out);
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<unsigned> *_pageLengths;
|
||||||
|
unsigned _fileSize;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
92
pascal/TextFile.cpp
Normal file
92
pascal/TextFile.cpp
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class TextFile {
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
unsigned size() const;
|
||||||
|
|
||||||
|
unsigned read(void *buffer, unsigned size, unsigned offset);
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
static unsigned decodeBlock(uint8_t *in, unsigned inSize, uint8_t *out);
|
||||||
|
|
||||||
|
unsigned _size;
|
||||||
|
std::vector<unsigned> _pageSize
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
unsigned decodeBlock(uint8_t *in, unsigned inSize, uint8_t *out)
|
||||||
|
{
|
||||||
|
const unsigned DLE = 16;
|
||||||
|
|
||||||
|
unsigned size = 0;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < inSize; ++i)
|
||||||
|
{
|
||||||
|
uint8_t c = in[i];
|
||||||
|
if (!c) break;
|
||||||
|
|
||||||
|
if ((c == DLE) && (i + 1 < inSize))
|
||||||
|
{
|
||||||
|
unsigned x = in[++i] - 32;
|
||||||
|
|
||||||
|
if (out)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < x; ++i)
|
||||||
|
*out++ = ' ';
|
||||||
|
}
|
||||||
|
size += x;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (out) *out++ = c;
|
||||||
|
++size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
// first 2 blocks are header information
|
||||||
|
|
||||||
|
_fileSize = 0;
|
||||||
|
|
||||||
|
unsigned pages = (_endBlock - _startBlock - 2) >> 1
|
||||||
|
uint8_t buffer[1024];
|
||||||
|
unsigned offset = 0;
|
||||||
|
|
||||||
|
for (unsigned i _startBlock + 2; i <= _endBlock; i += 2)
|
||||||
|
{
|
||||||
|
uint8_t buffer[1024];
|
||||||
|
unsigned dataSize = 0;
|
||||||
|
unsigned offset = 0;
|
||||||
|
unsigned size;
|
||||||
|
|
||||||
|
// load a 2-block page.
|
||||||
|
for (j = i; j <= _endBlock; ++j)
|
||||||
|
{
|
||||||
|
_device->readBlock(j, buffer + offset);
|
||||||
|
dataSize += j == _endBlock ? _lastByte : 512;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
size = decodeBlock(buffer, dataSize, NULL);
|
||||||
|
|
||||||
|
_pageSize.push_back(size);
|
||||||
|
_fileSize += size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
0
pascal/TextFile.h
Normal file
0
pascal/TextFile.h
Normal file
Loading…
Reference in New Issue
Block a user