text writing

git-svn-id: https://profuse.googlecode.com/svn/branches/v2@304 aa027e90-d47c-11dd-86d7-074df07e0730
This commit is contained in:
ksherlock 2010-05-31 00:06:51 +00:00
parent e3d0514c85
commit f07a6ecd8b
4 changed files with 216 additions and 11 deletions

View File

@ -6,6 +6,7 @@
#include <cerrno>
#include <Pascal/Pascal.h>
#include <Pascal/TextWriter.h>
#include <ProFUSE/auto.h>
#include <ProFUSE/Exception.h>
@ -176,12 +177,21 @@ int FileEntry::truncate(unsigned newSize)
if (fileKind() == kTextFile)
{
if (newSize)
throw ProFUSE::Exception(__METHOD__ ": unable to truncate text file.");
{
errno = EINVAL;
return -1;
}
newSize = 2; // text files have a 2-page scratch buffer for the editor.
if (_pageSize) _pageSize->clear();
if (_pageSize)
{
_pageSize->clear();
_fileSize = 0;
}
}
truncateCommon(newSize);
if (truncateCommon(newSize) != 0)
return -1;
_modification = Date::Today();
parent()->writeEntry(this);
@ -194,19 +204,22 @@ int FileEntry::truncate(unsigned newSize)
* updates _lastByte and _lastBlock but does
* not update _modification or commit to disk.
*/
void FileEntry::truncateCommon(unsigned newSize)
int FileEntry::truncateCommon(unsigned newSize)
{
#undef __METHOD__
#define __METHOD__ "FileEntry::truncateCommon"
unsigned currentSize = fileSize();
if (newSize == currentSize) return;
if (newSize == currentSize) return 0;
if (newSize > currentSize)
{
if (newSize > _maxFileSize)
throw ProFUSE::POSIXException(__METHOD__ ": Unable to expand file.", ENOSPC);
{
errno = ENOSPC;
return -1;
}
unsigned remainder = newSize - currentSize;
unsigned block = _lastBlock - 1;
@ -245,17 +258,65 @@ void FileEntry::truncateCommon(unsigned newSize)
_lastByte = newSize % 512;
if (_lastByte == 0) _lastByte = 512;
return 0;
}
int FileEntry::write(TextWriter &text)
{
unsigned blocks = text.blocks();
if (parent()->readOnly())
{
errno = EROFS;
return -1;
}
if (fileKind() != kTextFile)
{
errno = EINVAL;
return -1;
}
if (blocks * 512 > _maxFileSize)
{
errno = ENOSPC;
return -1;
}
for (unsigned i = 0; i < blocks; ++i)
{
void *buffer = text.data(i);
parent()->writeBlock(_firstBlock + i, buffer);
}
_modification = Date::Today();
_lastBlock = 1 + firstBlock() + blocks;
_lastByte = 512;
parent()->writeEntry(this);
parent()->sync();
return blocks * 512;
}
int FileEntry::write(uint8_t *buffer, unsigned size, unsigned offset)
{
#undef __METHOD__
#define __METHOD__ "FileEntry::write"
if (parent()->readOnly())
{
errno = EROFS;
return -1;
}
if (fileKind() == kTextFile)
{
throw ProFUSE::Exception(__METHOD__ ": Text Files are too weird.");
errno = EINVAL;
return -1;
}
unsigned currentSize = fileSize();
@ -265,17 +326,18 @@ int FileEntry::write(uint8_t *buffer, unsigned size, unsigned offset)
if (newSize > _maxFileSize)
{
throw ProFUSE::POSIXException(__METHOD__ ": Unable to expand file.", ENOSPC);
errno = ENOSPC;
return -1;
}
if (offset > currentSize)
{
truncateCommon(offset);
if (truncateCommon(offset) != 0) return -1;
}
// now write the data...
unsigned block = _firstBlock + offset / 512;
unsigned block = firstBlock() + offset / 512;
unsigned start = offset % 512;
unsigned remainder = size;

View File

@ -8,6 +8,8 @@
namespace Pascal {
class TextWriter;
class FileEntry : public Entry {
public:
@ -38,6 +40,8 @@ namespace Pascal {
int read(uint8_t *buffer, unsigned size, unsigned offset);
int write(uint8_t *buffer, unsigned size, unsigned offset);
int write(TextWriter& text);
int truncate(unsigned newSize);
@ -52,7 +56,7 @@ namespace Pascal {
void setName(const char *name);
void truncateCommon(unsigned newSize);
int truncateCommon(unsigned newSize);

102
Pascal/TextWriter.cpp Normal file
View File

@ -0,0 +1,102 @@
#include <Pascal/TextWriter.h>
#include <Pascal/FileEntry.h>
#include <ProFUSE/Exception.h>
#include <string>
#include <cstring>
using namespace Pascal;
TextWriter::TextWriter()
{
_offset = 0;
_current = new uint8_t[1024];
_blocks.push_back(new uint8_t[1024]); // 1024k for editor scratch data.
std::memset(_blocks.back(), 0, 1024);
std::memset(_current, 0, 1024);
}
TextWriter::~TextWriter()
{
std::vector<uint8_t *>::iterator iter;
if (_current) delete[] _current;
for (iter = _blocks.begin(); iter != _blocks.end(); ++iter)
{
delete[] *iter;
}
}
unsigned TextWriter::blocks() const
{
if (_offset == 0) return _blocks.size() * 2;
if (_offset <= 512) return _blocks.size() * 2 + 1;
return _blocks.size() * 2 + 2;
}
void *TextWriter::data(unsigned block) const
{
unsigned offset = (block & 0x01) * 512;
if (( block >> 1 ) < _blocks.size())
{
return _blocks[block >> 1] + offset;
}
if (block == _blocks.size())
{
if (offset > _offset) return NULL;
return _current + offset;
}
return NULL;
}
void TextWriter::writeLine(const char *line)
{
writeLine(line, std::strlen(line));
}
void TextWriter::writeLine(const char *line, unsigned length)
{
#undef __METHOD__
#define __METHOD__ "TextWriter::writeLine"
if (line == NULL) line = "";
std::string text(line, length);
if (length)
{
char c = text[length - 1];
if (c == 0x0a) text[length - 1] = 0x0d;
else if (c != 0x0d) text.push_back(0x0d);
FileEntry::Compress(text);
}
else
{
text.push_back(0x0d);
}
length = text.length();
if (length > 1024)
{
throw ProFUSE::Exception(__METHOD__ ": String is too long.");
}
if (_offset + length > 1024)
{
_blocks.push_back(_current);
_offset = 0;
_current = new uint8_t[1024];
std::memset(_current, 0, 1024);
}
std::memcpy(_current + _offset, text.data(), length);
_offset += length;
}

37
Pascal/TextWriter.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef __PASCAL_TEXTWRITER_H__
#define __PASCAL_TEXTWRITER_H__
#include <vector>
#include <stdint.h>
namespace Pascal {
class TextWriter {
public:
TextWriter();
~TextWriter();
unsigned blocks() const;
void *data(unsigned block) const;
void writeLine(const char *);
void writeLine(const char *, unsigned length);
private:
std::vector<uint8_t *> _blocks;
unsigned _offset;
uint8_t *_current;
};
}
#endif