?? chm.cpp
字號:
#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 + -