RedPuma

ArchiveFileStream

Oct 24th, 2013
294
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 5.54 KB | None | 0 0
  1. // Author: Marius Graefe
  2.  
  3. #include <fstream>
  4. #include <assert.h>
  5. #include <algorithm>
  6. #include <vector>
  7. #include <stdexcept>
  8. #include "filesystem.h"
  9.  
  10. namespace filesystem
  11. {
  12.  
  13. //Currently only works with _Elem = char!
  14. template<class _Elem, class _Traits>
  15. class ArchiveStreamBuf : public std::basic_streambuf<_Elem, _Traits>
  16. {
  17. private:
  18.     //returns false if file was not found in any mounted archive
  19.     bool getFileArchiveInfo(const char *path, fileinfo_t &info)
  20.     {
  21.         return m_fs->findFile(path, &info);
  22.     }
  23.  
  24. private:
  25.     typedef ArchiveStreamBuf<_Elem, _Traits> MyT;
  26.     typedef std::basic_streambuf<_Elem, _Traits> MybT;
  27.  
  28. public:
  29.     ArchiveStreamBuf(Filesystem *fs = NULL) :
  30.         m_file(NULL),
  31.         m_buf(1024),
  32.         m_fs(fs),
  33.         m_fileStart(0),
  34.         m_fileSize(0)
  35.     {
  36.         if(!m_fs)
  37.             m_fs = &Filesystem::GetInstance();
  38.     }
  39.  
  40.     ~ArchiveStreamBuf()
  41.     {
  42.         close();
  43.     }
  44.  
  45.     MyT *open(const char *filename, std::ios_base::openmode mode)
  46.     {
  47.         if((mode & std::ios_base::out) || !(mode & std::ios_base::in))
  48.             throw std::logic_error("Only input supported!");
  49.  
  50.         //file exists locally?
  51.         m_file = fopen(filename, "rb");
  52.         if(m_file)
  53.         {
  54.             m_fileStart = 0;
  55.             fseek(m_file, 0, SEEK_END);
  56.             m_fileSize = ftell(m_file);
  57.             fseek(m_file, 0, SEEK_SET);
  58.         }
  59.         else //Search archives
  60.         {
  61.             fileinfo_t info;
  62.             if(getFileArchiveInfo(filename, info) && (m_file = fopen(info.archiveName, "rb")))
  63.             {
  64.                 m_fileStart = info.fileStart;
  65.                 m_fileSize = info.fileSize;
  66.                 fseek(m_file, m_fileStart, SEEK_SET);
  67.             }
  68.         }
  69.  
  70.         if(m_file)
  71.         {
  72.             _Elem *end = &m_buf[0] + m_buf.size() * sizeof(_Elem);
  73.             MybT::setg(end, end, end); //invalidate pointers
  74.             return this;
  75.         }
  76.  
  77.         return NULL;
  78.     }
  79.  
  80.     MyT *open(const std::string &filename, std::ios_base::openmode mode)
  81.     {
  82.         return open(filename.c_str(), mode);
  83.     }
  84.  
  85.     MyT *close()
  86.     {
  87.         if(!m_file)
  88.             return NULL;
  89.         fclose(m_file);
  90.         m_file = NULL;
  91.         return this;
  92.     }
  93.  
  94.     bool is_open() const
  95.     {
  96.         return m_file != NULL;
  97.     }
  98.  
  99.     size_t getFileSize() const
  100.     {
  101.         return (size_t)m_fileSize;
  102.     }
  103.  
  104. private:
  105.     ArchiveStreamBuf(const MyT &other); //not defined
  106.     MyT &operator=(const MyT&); //not defined
  107.  
  108. protected:
  109.     virtual typename MybT::int_type underflow()
  110.     {
  111.         assert(MybT::gptr() >= MybT::eback() && MybT::gptr() <= MybT::egptr());
  112.         if(MybT::gptr() < MybT::egptr())
  113.             return _Traits::to_int_type(*MybT::gptr());
  114.         int pos = ftell(m_file) - m_fileStart;
  115.         int remaining = m_fileSize - pos;
  116.         if(remaining <= 0)
  117.             return _Traits::eof();
  118.         _Elem *start = &m_buf[0];
  119.         size_t n = fread(start, 1, std::min((int)m_buf.size(), remaining), m_file);
  120.         assert(n > 0);
  121.         MybT::setg(start, start, start + n);
  122.         return _Traits::to_int_type(*MybT::gptr());
  123.     }
  124.  
  125.     virtual typename MybT::pos_type seekoff(typename MybT::off_type off,
  126.         std::ios_base::seekdir way,
  127.         std::ios_base::openmode mode = std::ios_base::in)
  128.     {
  129.         assert(MybT::gptr() >= MybT::eback() && MybT::gptr() <= MybT::egptr());
  130.         int currPos = (ftell(m_file) - m_fileStart) - (size_t)(MybT::egptr() - MybT::gptr());
  131.         int absPos;
  132.         switch(way)
  133.         {
  134.         case std::ios_base::beg:
  135.             absPos = (int)off; break;
  136.         case std::ios_base::cur:
  137.             absPos = currPos + (int)off; break;
  138.         case std::ios_base::end:
  139.             absPos = m_fileSize + (int)off; break;
  140.         default:
  141.             return std::streampos(std::streamoff(-1));
  142.         }
  143.  
  144.         if(absPos == currPos)
  145.             return std::streampos(currPos);
  146.  
  147.         return seekpos(absPos, mode);
  148.     }
  149.  
  150.     virtual typename MybT::pos_type seekpos(typename MybT::pos_type pos,
  151.         std::ios_base::openmode mode = std::ios_base::in)
  152.     {
  153.         assert(MybT::gptr() >= MybT::eback() && MybT::gptr() <= MybT::egptr());
  154.         MybT::setg(MybT::egptr(), MybT::egptr(), MybT::egptr()); //invalidate pointers
  155.         if(pos < 0 || pos > m_fileSize)
  156.             return std::streampos(std::streamoff(-1));
  157.         int res = fseek(m_file, (int)pos + m_fileStart, SEEK_SET);
  158.         return res == 0 ? pos : std::streampos(std::streamoff(-1));
  159.     }
  160.    
  161.     virtual std::streamsize xsgetn(_Elem *ptr, std::streamsize count)
  162.     {
  163.         assert(MybT::gptr() >= MybT::eback() && MybT::gptr() <= MybT::egptr());
  164.         if(count > std::streamsize(std::numeric_limits<size_t>::max()))
  165.             return std::streamsize(-1);
  166.  
  167.         //first copy from our buffer
  168.         size_t remaining = (size_t)(MybT::gptr() - MybT::eback());
  169.         size_t read = 0;
  170.         if(remaining > 0)
  171.         {
  172.             read = std::min(remaining, (size_t)count);
  173.             std::memcpy(ptr, MybT::gptr(), read * sizeof(_Elem));
  174.         }
  175.         if((size_t)count > remaining) //if our buffer is depleted call fread to read the rest
  176.         {
  177.             read += fread(ptr + read * sizeof(_Elem), sizeof(_Elem), (size_t)count - read, m_file);
  178.             MybT::setg(MybT::egptr(), MybT::egptr(), MybT::egptr()); //invalidate pointers
  179.         }
  180.         return std::streamsize(read);
  181.     }
  182.  
  183.     virtual std::streamsize showmanyc()
  184.     {
  185.         return 0;
  186.     }
  187.  
  188.     //Unimplemented functions:
  189.     virtual typename MybT::int_type pbackfail(typename MybT::int_type meta = _Traits::eof()) {
  190.         throw std::logic_error("not supported.");
  191.     }
  192.     virtual MybT *setbuf(_Elem *buffer, std::streamsize count) {
  193.         throw std::logic_error("not supported.");
  194.     }
  195.     virtual typename MybT::int_type sync() {
  196.         throw std::logic_error("not supported");
  197.     }
  198.     virtual void imbue(const std::locale &loc) {
  199.         //m_fb.pubimbue(loc);
  200.     }
  201.     virtual std::streamsize xputn(const _Elem *ptr, std::streamsize count) {
  202.         throw std::logic_error("not supported");
  203.     }
  204.     virtual typename MybT::int_type overflow(typename MybT::int_type meta = _Traits::eof()) {
  205.         throw std::logic_error("not supported");
  206.     }
  207.  
  208. private:
  209.     FILE *m_file;
  210.     std::vector<_Elem> m_buf;
  211.     Filesystem *m_fs;
  212.     int m_fileStart;
  213.     int m_fileSize;
  214. };
  215.  
  216. }
Add Comment
Please, Sign In to add comment