mirror of
https://github.com/ksherlock/profuse.git
synced 2025-01-06 11:29:32 +00:00
text writing
git-svn-id: https://profuse.googlecode.com/svn/branches/v2@304 aa027e90-d47c-11dd-86d7-074df07e0730
This commit is contained in:
parent
e3d0514c85
commit
f07a6ecd8b
@ -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;
|
||||
|
||||
|
@ -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
102
Pascal/TextWriter.cpp
Normal 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
37
Pascal/TextWriter.h
Normal 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
|
Loading…
Reference in New Issue
Block a user