From f07a6ecd8b1262cec8772e49ea89c20a908e98ad Mon Sep 17 00:00:00 2001 From: ksherlock Date: Mon, 31 May 2010 00:06:51 +0000 Subject: [PATCH] text writing git-svn-id: https://profuse.googlecode.com/svn/branches/v2@304 aa027e90-d47c-11dd-86d7-074df07e0730 --- Pascal/FileEntry.cpp | 82 ++++++++++++++++++++++++++++----- Pascal/FileEntry.h | 6 ++- Pascal/TextWriter.cpp | 102 ++++++++++++++++++++++++++++++++++++++++++ Pascal/TextWriter.h | 37 +++++++++++++++ 4 files changed, 216 insertions(+), 11 deletions(-) create mode 100644 Pascal/TextWriter.cpp create mode 100644 Pascal/TextWriter.h diff --git a/Pascal/FileEntry.cpp b/Pascal/FileEntry.cpp index 5bf9bef..546bb5b 100644 --- a/Pascal/FileEntry.cpp +++ b/Pascal/FileEntry.cpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -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; diff --git a/Pascal/FileEntry.h b/Pascal/FileEntry.h index 8774398..d5b0eab 100644 --- a/Pascal/FileEntry.h +++ b/Pascal/FileEntry.h @@ -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); diff --git a/Pascal/TextWriter.cpp b/Pascal/TextWriter.cpp new file mode 100644 index 0000000..dff4a79 --- /dev/null +++ b/Pascal/TextWriter.cpp @@ -0,0 +1,102 @@ + +#include +#include + +#include + +#include +#include + +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::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; +} \ No newline at end of file diff --git a/Pascal/TextWriter.h b/Pascal/TextWriter.h new file mode 100644 index 0000000..23d0902 --- /dev/null +++ b/Pascal/TextWriter.h @@ -0,0 +1,37 @@ + +#ifndef __PASCAL_TEXTWRITER_H__ +#define __PASCAL_TEXTWRITER_H__ + +#include +#include + +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 _blocks; + unsigned _offset; + + uint8_t *_current; + + }; + +} + + +#endif \ No newline at end of file