⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 chm.cpp

📁 It is a chm file viewer lib with source code
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include <iostream>#include <cstdio>#include <streambuf>#include <map>#include <algorithm>#include <cassert>#include "chmxx.h"#include "chm_lib.h"#include "tagreader.h"using std::string;using std::vector;using std::list;using std::map;using namespace chm;namespace {  class chmstreambuf : public std::streambuf {  public:    chmstreambuf (chmFile *chm, chmUnitInfo ui, size_t buf_size = 1024) : chm(chm), ui(ui), addr(0), buf_size(buf_size)    {      buf = new char[buf_size];      is_cached = false;      file_size = ui.length;      setg (buf, buf + buf_size, buf + buf_size);      if ( buf_size == file_size ) underflow(); // force loading of entire buffer, no more loads are done    }    chmstreambuf (const char *b, size_t buf_size) : buf((char *)buf), buf_size(buf_size)    {      is_cached = true;      setg (buf, buf, buf + buf_size);      addr = buf_size;      file_size = buf_size;    }    virtual ~chmstreambuf ()    {      if ( !is_cached ) delete buf;    }    virtual pos_type seekoff (off_type amount, std::ios_base::seekdir dir, std::ios_base::openmode)    {      LONGUINT64 naddr;      if (dir == std::ios_base::beg ) {          naddr = amount;      } else if ( dir == std::ios_base::cur ) {          LONGUINT64 cur_addr = addr - (egptr() - gptr()); // determine current real read position          naddr = cur_addr + amount;          if ( amount == 0 ) { return naddr; } // tellg optimization      } else if ( dir == std::ios_base::end ) {          naddr = file_size + amount;      } else {          return pos_type(off_type(-1));      }      if ( naddr >= file_size )          return pos_type(off_type(-1));      // try to optimise if the seek is inside our buffer      LONGUINT64 low = addr - (egptr() - eback());      LONGUINT64 high = addr;      if ( naddr >= low && naddr < high ) {          setg (eback(), egptr() - (addr - naddr), egptr());          return naddr;      }      setg (buf, buf + buf_size, buf + buf_size);      addr = naddr;      return addr;    }    virtual pos_type seekpos (pos_type pos, std::ios_base::openmode om)    {      return seekoff (pos, std::ios_base::beg, om);    }    virtual std::streamsize showmanyc ()    {      return (egptr() - gptr()) + (file_size - addr);    }    std::streamsize read_left () const    {      return (egptr() - gptr()) + (file_size - addr);    }    std::streamsize xsgetn(char_type* __s, std::streamsize __n)    {      std::streamsize r = 0;      if ( gptr() < egptr() ) {          if ( egptr() - gptr() > __n ) {              std::memcpy (__s, gptr(), __n);              gbump (__n);              return __n;          } else {              r = egptr() - gptr();              std::memcpy (__s, gptr(), r);          }      }      LONGUINT64 m = chm_retrieve_object (chm, &ui, (unsigned char *)(__s + r), addr, __n - r);      addr += m;      setg (buf, buf + buf_size, buf + buf_size);      return r + m;    }    virtual int_type underflow ()    {      if ( gptr() < egptr () )          return *gptr();      if ( addr >= file_size ) return traits_type::eof();      std::streamsize r = xsgetn (buf, buf_size);      setg (buf, buf, buf + r);      if ( r == 0 )          return traits_type::eof();      return *gptr();    }  private:    chmFile *chm;    chmUnitInfo ui;    LONGUINT64 addr;    char *buf;    size_t buf_size;    size_t file_size;    bool is_cached;  };} // namespace {chm::chmfile::chmfile (const string& path) : path(path){  chm = chm_open (path.c_str());  tree = NULL;  if ( !chm ) return;  chmistream in(*this, "/#SYSTEM");  if ( in ) {      in.get_dword();      while ( in.read_left() ) {        size_t type = in.get_word();        size_t len = in.get_word();        vector<char> data(len);        in.read (&data[0], len);//        printf ("type = %ld, len = %ld, data = [%s]\n", type, len, &data[0]);        switch (type) {          case 0:            topics_file = "/" + string(data.begin(), data.end() - 1);            break;          case 1:            index_file = "/" + string(data.begin(), data.end() - 1);            break;          case 2:            home_file = "/" + string(data.begin(), data.end() - 1);            break;          case 3:            title = string(data.begin(), data.end() - 1);            break;          case 6:            if ( topics_file.empty() )              {                string t = string(data.begin(), data.end() - 1);                if ( file_exists (t + ".hhc") )                    topics_file = "/" + t + ".hhc";                if ( file_exists (t + ".hhk") )                    index_file = "/" + t + ".hhk";              }            break;          case 9:            generator = string(data.begin(), data.end() - 1);            break;        }      }  }  if ( topics_file.empty() && index_file.empty() ) {      vector<char> buf;      if ( read ("/#STRINGS", buf) && buf.size() ) {        vector<char>::iterator i = buf.begin();        i++;  // skip first byte;        while ( i != buf.end() ) {          string next = string(i, std::find (i, buf.end(), 0));          if ( next.size() > 4 ) {            string prefix = next.substr(next.size() - 4);            std::transform (prefix.begin(), prefix.end(), prefix.begin(), (int(*)(int))std::tolower);//            std::cout << next << " " << prefix << std::endl;            if ( prefix == ".hhc" )                topics_file = "/" + next;            else if ( prefix == ".hhk" )                index_file = "/" + next;          }          i += next.size() + 1;        }      }  }}const chm::chm_topics_tree * chm::chmfile::get_topics_tree () const{  if ( tree || topics_file.empty() ) return tree;  vector<char> buf;  if ( read (topics_file, buf) ) {      tree = new chm_topics_tree ();      tree->parent = NULL;      chm_topics_tree *cur = tree;      chm_topics_tree *last = tree;      string str (buf.begin(), buf.end());      buf.clear(); // release memory  //        std::cout << str << std::endl;      tagreader tr(str);//      std::cerr << "Topics tree size in bytes: " << str.size() << "\n";      while ( tr.has_next() ) {          tagreader::tagstruct s = tr.get_next();          if ( s.tag == "object" && s.elems["type"] == "text/sitemap" ) {            s = tr.get_next ();            last = new chm_topics_tree ();            last->parent = cur;            cur->children.push_back (last);            while ( s.tag != "/object" ) {                if ( s.tag == "param" ) {                    string name = s.elems["name"];                    string value = s.elems["value"];                    if ( name == "Name" ) {                        last->title = value;                    } else if ( name == "Local" ) {                        last->path = "/" + value;                    }                }                if ( !tr.has_next () ) break; // faulty file                s = tr.get_next();            }            continue;          }          if ( s.tag == "ul" && s.tag_level > 1 ) {            cur = last;            continue;          }          if ( s.tag == "/ul" && s.tag_level > 0 && cur->parent ) {            cur = cur->parent;            continue;          }      }  }  return tree;}bool chm::chmfile::is_open () const{  return chm != NULL;}std::streambuf* chm::chmfile::open (const string& path, size_t buf_size) const{  if ( !cache_data.empty() ) {  // check cache data first      cache_data_t::const_iterator it = cache_data.find(path);      if ( it != cache_data.end() )          return new chmstreambuf (&it->second[0], it->second.size());  }  struct chmUnitInfo ui;  if ( chm_resolve_object (chm, path.c_str(), &ui) == CHM_RESOLVE_FAILURE )      return NULL;  return new chmstreambuf(chm, ui, buf_size);}std::streamsize chm::chmfile::file_size (const string& path) const{  struct chmUnitInfo ui;  if ( chm_resolve_object (chm, path.c_str(), &ui) == CHM_RESOLVE_FAILURE )      return 0;  else      return ui.length;}bool chm::chmfile::file_exists (const string& path) const{  struct chmUnitInfo ui;  return chm_resolve_object (chm, path.c_str(), &ui) != CHM_RESOLVE_FAILURE;}bool chm::chmfile::read (const string& path, std::ostream& out) const{  struct chmUnitInfo ui;  if ( chm_resolve_object (chm, path.c_str(), &ui) == CHM_RESOLVE_FAILURE )      return false;  chmstreambuf buf(chm, ui);  out << &buf;  return true;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -