入力streamの分離 †このページの必要全ファイルは 入力streamと contents 処理を分離する。そのため、CMyReader class を導入する。また、先頭の一定量を見て、contentsの自動分類を行う。この分類はcontents処理の前に行う必要がある。またstreamによっては先頭に戻ることは不可能である場合もあるので、最初のreadの前に一定量bufferingして分類をしておく必要がある。 // myreader.h #ifndef MYREADER_H_INCLUDED #define MYREADER_H_INCLUDED namespace mylib { class CMyReader { public: virtual ~CMyReader(); virtual bool Read(unsigned char* buffer, size_t maxread, size_t& nread); virtual int GetOctet(); const unsigned char* Buffer() const; size_t Filled() const; public: static const int MY_EOF = (-1); static const int MY_BUFSIZE = 1024; protected: CMyReader(); virtual bool Fill(unsigned char* buffer, size_t maxread, size_t& nread); protected: bool m_bEofDetected; size_t m_nFilled; size_t m_nRead; unsigned char m_bBuffer[MY_BUFSIZE]; }; } // namespace mylib #endif // MYREADER_H_INCLUDED Buffering してある場合、buffer の残量と read の size が必ずしも一致するわけではないので論理が結構面倒である。そこで、派生 class では open/close 関係の他 Fill() のみ実装すれば済むようにしておく。 // myreader.cpp #include <windows.h> #include "myreader.h" namespace mylib { CMyReader::CMyReader() { m_bEofDetected = false; m_nFilled = 0; m_nRead = 0; } CMyReader::~CMyReader() { } bool CMyReader::Fill(unsigned char* buffer, size_t maxread, size_t& nread) { nread = 0; return false; } bool CMyReader::Read(unsigned char* buffer, size_t maxread, size_t& nread) { bool result = false; if(m_nFilled >= (m_nRead + maxread)) { for(size_t n = 0; n < maxread; n++) buffer[n] = m_bBuffer[m_nRead++]; nread = maxread; result = true; } else { size_t k = 0; for(size_t n = m_nRead; n < m_nFilled; n++) buffer[k++] = m_bBuffer[n]; m_nRead = m_nFilled = 0; if(m_bEofDetected) { nread = k; return true; } m_nRead = m_nFilled = 0; result = Fill(&buffer[k], (maxread - k), nread); if(nread == 0) m_bEofDetected = true; nread = nread + k; } return result; } int CMyReader::GetOctet() { if(m_nRead >= m_nFilled) { m_nFilled = m_nRead = 0; if(m_bEofDetected) return MY_EOF; if(!Fill(m_bBuffer, MY_BUFSIZE, m_nFilled)) return MY_EOF; if(m_nFilled == 0) { m_bEofDetected = true; return MY_EOF; } } int c = (int)m_bBuffer[m_nRead++] & 255; return c; } const unsigned char* CMyReader::Buffer() const { return m_bBuffer; } size_t CMyReader::Filled() const { return m_nFilled; } } //namespace mylib CMyFileReader class の導入 †いままでの file を読む部分を CMyReader から派生させた CMyFileReader class とする。上記に述べたように CMyReader で buffering は処理するので、必要なのは open/close // myfilerd.h #ifndef MYFILERD_H_INCLUDED #define MYFILERD_H_INCLUDED #include "myreader.h" namespace mylib { class CMyFileReader : public CMyReader { public: CMyFileReader(const TCHAR* szName); virtual ~CMyFileReader(); protected: virtual bool Fill(unsigned char* buffer, size_t maxread, size_t& nread); private: HANDLE m_hFile; }; } // namespace mylib #endif // MYFILERD_H_INCLUDED // myfilerd.cpp #include <windows.h> #include "myfilerd.h" namespace mylib { CMyFileReader::CMyFileReader(const TCHAR* szName) { m_hFile = ::CreateFile(szName, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); if(m_hFile == INVALID_HANDLE_VALUE) return; Fill(m_bBuffer, MY_BUFSIZE, m_nFilled); } CMyFileReader::~CMyFileReader() { if(m_hFile != INVALID_HANDLE_VALUE) ::CloseHandle(m_hFile); } bool CMyFileReader::Fill(unsigned char* buffer, size_t maxread, size_t& nread) { DWORD dwRead = 0; if(!::ReadFile(m_hFile, buffer, maxread, &dwRead, 0)) { nread = 0; return false; } nread = (size_t)dwRead; return true; } } // namespace mylib |