//////////////////////////////////////////////////////////////////// // Filters.h // // Copyright 2007 cDc@seacave // Distributed under the Boost Software License, Version 1.0 // (See http://www.boost.org/LICENSE_1_0.txt) #ifndef __SEACAVE_FILTERS_H__ #define __SEACAVE_FILTERS_H__ // I N C L U D E S ///////////////////////////////////////////////// #include "Streams.h" // D E F I N E S /////////////////////////////////////////////////// namespace SEACAVE { // S T R U C T S /////////////////////////////////////////////////// template class BufferedInputStream : public LayerInputStream { public: typedef LayerInputStream Base; BufferedInputStream(InputStream* aStream, size_t aBufSize) : Base(aStream), buf(new uint8_t[aBufSize]), bufSize(aBufSize), cache(0), pos(0) { ASSERT(aBufSize > 0); } virtual ~BufferedInputStream() { delete[] buf; } size_t read(void* wbuf, size_t len) override { uint8_t* b = (uint8_t*)wbuf; const size_t l2 = len; do { ASSERT(pos <= cache); if (pos == cache) { if (len >= bufSize) { const size_t r = Base::read(b, len); if (r == STREAM_ERROR) return STREAM_ERROR; return l2 - len + r; } pos = 0; switch (cache = Base::read(buf, bufSize)) { case 0: return l2 - len; case STREAM_ERROR: return STREAM_ERROR; } } const size_t n = MINF(cache - pos, len); memcpy(b, buf + pos, n); b += n; pos += n; len -= n; } while (len > 0); return l2; } bool setPos(size_f_t wpos) override { pos = cache = 0; return Base::setPos(wpos); } size_f_t getPos() const override { const size_f_t r = Base::getPos(); if (r == SIZE_NA) return SIZE_NA; return r-(cache-pos); } enum { LAYER_ID_IN=1 }; InputStream* getInputStream(int typ=InputStream::LAYER_ID_IN) override { return (typ == LAYER_ID_IN ? static_cast(this) : Base::getInputStream(typ)); } private: uint8_t* const buf; const size_t bufSize; size_t cache; size_t pos; }; template class BufferedOutputStream : public LayerOutputStream { public: typedef LayerOutputStream Base; BufferedOutputStream(OutputStream* aStream, size_t aBufSize) : Base(aStream), buf(new uint8_t[aBufSize]), bufSize(aBufSize), pos(0) { } virtual ~BufferedOutputStream() { flush(); delete[] buf; } size_t write(const void* wbuf, size_t len) override { if (len < bufSize - pos) { memcpy(buf + pos, (const uint8_t*)wbuf, len); pos += len; return len; } uint8_t* b = (uint8_t*)wbuf; const size_t l2 = len; do { if (pos == bufSize) { if (Base::write(buf, bufSize) == STREAM_ERROR) return STREAM_ERROR; pos = 0; if (len < bufSize) { if (Base::write(b, len) == STREAM_ERROR) return STREAM_ERROR; break; } } const size_t n = MINF(bufSize - pos, len); memcpy(buf + pos, b, n); b += n; pos += n; len -= n; } while (len > 0); return l2; } size_f_t getSize() const override { const size_f_t r = Base::getSize(); if (r == SIZE_NA) return SIZE_NA; return r + pos; } bool setPos(size_f_t wpos) override { if (pos > 0) { const size_t ret = Base::write(buf, pos); pos = 0; if (ret == STREAM_ERROR) return false; } return Base::setPos(wpos); } size_f_t getPos() const override { const size_f_t r = Base::getPos(); if (r == SIZE_NA) return SIZE_NA; return r + pos; } size_t flush() override { size_t ret = 0; if (pos > 0) { ret = Base::write(buf, pos); pos = 0; if (ret == STREAM_ERROR) return STREAM_ERROR; } return ret + Base::flush(); } enum { LAYER_ID_OUT=1 }; OutputStream* getOutputStream(int typ=OutputStream::LAYER_ID_OUT) override { return (typ == LAYER_ID_OUT ? static_cast(this) : Base::getOutputStream(typ)); } private: uint8_t* const buf; const size_t bufSize; size_t pos; }; /*----------------------------------------------------------------*/ template class FilteredInputStream : public LayerInputStream { public: typedef LayerInputStream Base; FilteredInputStream(InputStream* pFile, size_t nFilteredSize, size_t nBufSize, void* pData) : Base(pFile), buf(new uint8_t[nBufSize]), filteredSize(nFilteredSize), bufSize(nBufSize), valid(0), pos(0), filter(pData), more(true) {} virtual ~FilteredInputStream() { delete[] buf; } /** * Read data through filter, keep calling until len returns 0. * @param rbuf Data buffer * @param len Buffer size on entry, bytes actually read on exit * @return Length of data in buffer */ size_t read(void* rbuf, size_t len) override { uint8_t* rb = (uint8_t*)rbuf; const size_t l2 = len; while (more && len) { if (pos == valid) { valid = Base::read(buf, bufSize); if (valid == STREAM_ERROR) return STREAM_ERROR; pos = 0; } size_t m = valid - pos; size_t n = len; more = filter(buf + pos, m, rb, n); pos += m; rb += n; len -= n; } return l2-len; } size_f_t getSize() const override { return filteredSize; } bool setPos(size_f_t wpos) override { valid = pos = 0; return Base::setPos(wpos); } size_f_t getPos() const override { const size_f_t r = Base::getPos(); if (r == SIZE_NA) return SIZE_NA; return r-(valid-pos); } enum { LAYER_ID_IN=2 }; InputStream* getInputStream(int typ=InputStream::LAYER_ID_IN) override { return (typ == LAYER_ID_IN ? static_cast(this) : Base::getInputStream(typ)); } private: uint8_t* const buf; const size_t filteredSize; const size_t bufSize; size_t valid; size_t pos; Filter filter; bool more; }; template class FilteredOutputStream : public LayerOutputStream { public: typedef LayerOutputStream Base; FilteredOutputStream(OutputStream* aFile, size_t aBufSize, void* pData) : Base(aFile), buf(new uint8_t[aBufSize]), bufSize(aBufSize), filter(pData), flushed(false) {} virtual ~FilteredOutputStream() { flush(); delete[] buf; } size_t write(const void* wbuf, size_t len) override { if (flushed) return STREAM_ERROR; const uint8_t* wb = (const uint8_t*)wbuf; size_t written = 0; while (len > 0) { size_t n = bufSize; size_t m = len; const bool more = filter(wb, m, buf, n); wb += m; len -= m; const size_t r = Base::write(buf, n); if (r == STREAM_ERROR) return STREAM_ERROR; written += r; if (!more) { if (len > 0) return STREAM_ERROR; flushed = true; return written; } } return written; } size_t flush() override { if (flushed) return Base::flush(); flushed = true; size_t written = 0; while (true) { size_t n = bufSize; size_t zero = 0; bool more = filter(NULL, zero, buf, n); written += Base::write(buf, n); if (!more) break; } const size_t r = Base::flush(); if (r == STREAM_ERROR) return STREAM_ERROR; return written + r; } enum { LAYER_ID_OUT=2 }; OutputStream* getOutputStream(int typ=OutputStream::LAYER_ID_OUT) override { return (typ == LAYER_ID_OUT ? static_cast(this) : Base::getOutputStream(typ)); } private: uint8_t* const buf; const size_t bufSize; Filter filter; bool flushed; }; /*----------------------------------------------------------------*/ #ifdef _UNICODE #define TOKEN_SIZE 2 //in bytes #else #define TOKEN_SIZE 1 //in bytes #endif #define TOKEN_MAXBUF (2048*TOKEN_SIZE) //in bytes #define TOKEN_MAXIGN 32 //in TCHARs template class TokenInputStream : public LayerInputStream { public: typedef LayerInputStream Base; TokenInputStream(InputStream* aStream, TCHAR aToken=_T('\n')) : Base(aStream), pos(TOKEN_MAXBUF), eos(false), token(aToken) { arrIgnore[0] = _T('\0'); } virtual ~TokenInputStream() { } void emptyBuffer() { setPos(getPos()); } TCHAR getToken() const { return token; } void setToken(TCHAR aToken) { token = aToken; } LPCTSTR getTrimTokens() const { return arrIgnore; } size_t setTrimTokens(LPCTSTR szIgnore) { const size_t len = _tcslen(szIgnore); if (len >= TOKEN_MAXIGN) return 0; _tcscpy(arrIgnore, szIgnore); return len; } LPTSTR trimFrontLine(LPTSTR line) { while (line[0] != _T('\0')) { if (_tcschr(arrIgnore, line[0]) == NULL) return line; ++line; } return line; } LPTSTR trimFrontLine(MemFile& memFile) { memFile.ensureSize(1); LPTSTR line = (LPTSTR)memFile.getData(); line[memFile.getSizeLeft()] = _T('\0'); LPTSTR newLine = trimFrontLine(line); memFile.movePos(newLine-line); return newLine; } size_t trimBackLine(LPTSTR line) { const size_t len = _tcslen(line); size_t i = len; while (i > 0 && line[--i] != _T('\0')) { if (_tcschr(arrIgnore, line[i]) == NULL) return len-(i+1); line[i] = _T('\0'); } return len; } size_t trimBackLine(MemFile& memFile) { memFile.ensureSize(1); LPTSTR line = (LPTSTR)memFile.getData(); line[memFile.getSizeLeft()] = _T('\0'); const size_t trimedSize = trimBackLine(line); memFile.moveSize(-((size_f_t)trimedSize)); return trimedSize; } // revert the deleted token during the last readLine() void restoreToken() { LPTSTR line = (LPTSTR)buf; ASSERT(pos > 0); line[--pos] = token; } size_t readLine(LPTSTR wbuf, size_t len) { if (eos) return 0; uint8_t* b = (uint8_t*)wbuf; const size_t l2 = len; // process chunks of TOKEN_MAXBUF bytes while (len >= TOKEN_MAXBUF / TOKEN_SIZE) { const size_t n = read(b, TOKEN_MAXBUF); if (n == STREAM_ERROR) return STREAM_ERROR; *((TCHAR*)(b+n)) = _T('\0'); LPTSTR t = _tcschr((TCHAR*)b, token); // if token found... if (t != NULL) { // ... set the end of line and return it t[0] = _T('\0'); if (n == TOKEN_SIZE && len != 1) { eos = true; return l2-len; } ++t; const size_t bytesParsed = (uint8_t*)t-b; const size_t bytesNotParsed = n - bytesParsed; pos = TOKEN_MAXBUF - bytesNotParsed; // store the unprocessed data memcpy(buf+pos, (uint8_t*)t, bytesNotParsed); len -= (bytesParsed - TOKEN_SIZE) / TOKEN_SIZE; return l2-len; } len -= n / TOKEN_SIZE; // if end of stream return if (n < TOKEN_MAXBUF) { eos = true; return l2-len; } b += n; // if we reached the end of the buffer, signal it if (len == 0) return l2+1; } // process the last sub-chunk part const size_t n = read(b, len*TOKEN_SIZE); if (n == STREAM_ERROR) return STREAM_ERROR; *((TCHAR*)(b+n)) = _T('\0'); LPTSTR t = _tcschr((TCHAR*)b, token); // if token found... if (t != NULL) { // ... set the end of line and return it t[0] = _T('\0'); if (n == TOKEN_SIZE && len != 1) { eos = true; return l2-len; } ++t; const size_t bytesParsed = (uint8_t*)t-b; const size_t bytesNotParsed = n - bytesParsed; pos = TOKEN_MAXBUF - bytesNotParsed; // store the unprocessed data memcpy(buf+pos, (uint8_t*)t, bytesNotParsed); len -= (bytesParsed - TOKEN_SIZE) / TOKEN_SIZE; return l2-len; } // if end of stream return if (n < len * TOKEN_SIZE) { eos = true; return n / TOKEN_SIZE; } // we reached the end of the buffer, signal it return l2+1; } size_t readLine(MemFile& memFile) { if (eos) return 0; // make sure we read one full line const size_f_t oldSize = memFile.getSize(); while (true) { memFile.ensureSize((4096+1)*TOKEN_SIZE); const size_t ret = readLine((LPTSTR)(memFile.getBuffer()+memFile.getSize()), 4096); if (ret == STREAM_ERROR) return STREAM_ERROR; if (ret <= 4096) { memFile.growSize(ret*TOKEN_SIZE); break; } memFile.growSize(4096*TOKEN_SIZE); } return size_t(memFile.getSize()-oldSize); } // read all to the memfile size_t read(MemFile& memFile) { if (eos) return 0; const size_t len = (size_t)(Base::getSize() - getPos()); memFile.ensureSize(len); const size_t ret = read(memFile.getBuffer()+memFile.getSize(), len); if (ret == STREAM_ERROR) return STREAM_ERROR; memFile.growSize(ret); return ret; } size_t read(void* wbuf, size_t len) override { size_t n = 0; if (pos < TOKEN_MAXBUF) { n = TOKEN_MAXBUF-pos; if (n > len) n = len; memcpy(wbuf, buf+pos, n); len -= n; pos += n; } if (len == 0) return n; const size_t r = Base::read((uint8_t*)wbuf+n, len); if (r == STREAM_ERROR) return STREAM_ERROR; return n+r; } bool setPos(size_f_t wpos) override { eos = false; pos = TOKEN_MAXBUF; return Base::setPos(wpos); } size_f_t getPos() const override { const size_f_t r = Base::getPos(); if (r == SIZE_NA) return SIZE_NA; return r-(TOKEN_MAXBUF-pos); } bool isEOS() const { return eos; } enum { LAYER_ID_IN=5 }; InputStream* getInputStream(int typ=InputStream::LAYER_ID_IN) override { return (typ == LAYER_ID_IN ? static_cast(this) : Base::getInputStream(typ)); } private: uint8_t buf[TOKEN_MAXBUF+TOKEN_SIZE]; size_t pos; bool eos; TCHAR token; TCHAR arrIgnore[TOKEN_MAXIGN]; }; /*----------------------------------------------------------------*/ template class MaskInputStream : public LayerInputStream { public: typedef LayerInputStream Base; MaskInputStream(InputStream* aStream, size_f_t nPos, size_f_t nSize) : Base(aStream), startPos(nPos), size(nSize), pos(0) { } virtual ~MaskInputStream() { } size_t read(void* wbuf, size_t len) override { if (pos >= size) return 0; if (!Base::setPos(startPos + pos)) return STREAM_ERROR; if (pos+(size_f_t)len > size) len = (size_t)(size - pos); const size_t r = Base::read(wbuf, len); if (r == STREAM_ERROR) return STREAM_ERROR; pos += r; return r; } size_f_t getSize() const override { return size; } bool setPos(size_f_t wpos) override { if (wpos > size) pos = size; else pos = wpos; return true; } size_f_t getPos() const override { return pos; } enum { LAYER_ID_IN=6 }; InputStream* getInputStream(int typ=InputStream::LAYER_ID_IN) override { return (typ == LAYER_ID_IN ? static_cast(this) : Base::getInputStream(typ)); } private: const size_f_t size; const size_f_t startPos; size_f_t pos; }; /*----------------------------------------------------------------*/ } // namespace SEACAVE #endif // __SEACAVE_FILTERS_H__