📄 xchmfile.cpp
字号:
else tagword = tag.toLower();// qDebug ("tag: '%s', tagword: '%s'\n", tag.toAscii().constData(), tagword.toAscii().constData()); // <OBJECT type="text/sitemap"> - a topic entry if ( tagword == "object" && tag.indexOf ("text/sitemap", 0, Qt::CaseInsensitive) != -1 ) in_object = true; else if ( tagword == "/object" && in_object ) { // a topic entry closed. Add a tree item if ( !name.isNull() ) { QDomElement * item = new QDomElement(); if ( !root_created ) indent = 0; QString url = urls.join ("|"); // Add item into the tree if ( !indent ) { *item = tree->createElement(name); item->setAttribute("ViewportName",url); item->setAttribute("Icon",imagenum); tree->appendChild(*item); } else { if ( !rootentry[indent-1] ) qFatal("CHMFile::ParseAndFillTopicsTree: child entry %d with no root entry!", indent-1); *item = tree->createElement(name); item->setAttribute("ViewportName",url); item->setAttribute("Icon",imagenum); rootentry[indent-1]->appendChild(*item); } lastchild[indent] = item; if ( indent == 0 || !rootentry[indent] ) { rootentry[indent] = item; root_created = true; } // There are no 'titles' in index file if ( add2treemap ) { insertIntoUrlMaps(m_UrlPage,m_PageUrl,url,pnum); } } else { if ( !urls.isEmpty() ) qDebug ("CHMFile::ParseAndFillTopicsTree: <object> tag with url \"%s\" is parsed, but name is empty.", urls[0].toAscii().constData()); else qDebug ("CHMFile::ParseAndFillTopicsTree: <object> tag is parsed, but both name and url are empty."); } name = QString::null; urls.clear(); in_object = false; imagenum = defaultimagenum; } else if ( tagword == "param" && in_object ) { // <param name="Name" value="First Page"> int offset; // strlen("param ") QString name_pattern = "name=", value_pattern = "value="; QString pname, pvalue; if ( (offset = tag.indexOf (name_pattern, 0, Qt::CaseInsensitive)) == -1 ) qFatal ("CHMFile::ParseAndFillTopicsTree: bad <param> tag '%s': no name=\n", tag.toAscii().constData()); // offset+5 skips 'name=' offset = findStringInQuotes (tag, offset + name_pattern.length(), pname, true, false); pname = pname.toLower(); if ( (offset = tag.indexOf (value_pattern, offset, Qt::CaseInsensitive)) == -1 ) qFatal ("CHMFile::ParseAndFillTopicsTree: bad <param> tag '%s': no value=\n", tag.toAscii().constData()); // offset+6 skips 'value=' findStringInQuotes (tag, offset + value_pattern.length(), pvalue, false, true);// qDebug ("<param>: name '%s', value '%s'", pname.toAscii().constData(), pvalue.toAscii().constData()); if ( pname == "name" ) name = pvalue; else if ( pname == "local" ) urls.push_back (KCHMUrl::makeURLabsoluteIfNeeded(pvalue)); else if ( pname == "see also" && asIndex && name != pvalue ) urls.push_back (KCHMUrl::makeURLabsoluteIfNeeded(":" + pvalue)); else if ( pname == "imagenumber" ) { bool bok; int imgnum = pvalue.toInt (&bok); if ( bok && imgnum >= 0 && (unsigned) imgnum < MAX_BUILTIN_ICONS ) imagenum = imgnum; } } else if ( tagword == "ul" ) // increase indent level { // Fix for buggy help files if ( ++indent >= MAX_NEST_DEPTH ) qFatal("CHMFile::ParseAndFillTopicsTree: max nest depth (%d) is reached, error in help file", MAX_NEST_DEPTH); lastchild[indent] = 0; rootentry[indent] = 0; } else if ( tagword == "/ul" ) // decrease indent level { if ( --indent < 0 ) indent = 0; rootentry[indent] = 0; } pos = i; } return true;}bool CHMFile::ParseHhcAndFillTree (const QString& file, K3ListView *tree, bool asIndex){ chmUnitInfo ui; const int MAX_NEST_DEPTH = 256; if(file.isEmpty() || !ResolveObject(file, &ui)) return false; QString src; GetFileContentAsString(src, &ui); if(src.isEmpty()) return false; unsigned int defaultimagenum = asIndex ? KCHMImageType::IMAGE_INDEX : KCHMImageType::IMAGE_AUTO; unsigned int imagenum = defaultimagenum; int pos = 0, indent = 0; bool in_object = false, root_created = false; QString name; QStringList urls; KCHMMainTreeViewItem * rootentry[MAX_NEST_DEPTH]; KCHMMainTreeViewItem * lastchild[MAX_NEST_DEPTH]; memset (lastchild, 0, sizeof(*lastchild)); memset (rootentry, 0, sizeof(*rootentry)); // Split the HHC file by HTML tags int stringlen = src.length(); while ( pos < stringlen && (pos = src.indexOf ('<', pos)) != -1 ) { int i, word_end = 0; for ( i = ++pos; i < stringlen; i++ ) { // If a " or ' is found, skip to the next one. if ( (src[i] == '"' || src[i] == '\'') ) { // find where quote ends, either by another quote, or by '>' symbol (some people don't know HTML) int nextpos = src.indexOf (src[i], i+1); if ( nextpos == -1 && (nextpos = src.indexOf ('>', i+1)) == -1 ) { qWarning ("CHMFile::ParseHhcAndFillTree: corrupted TOC: %s", src.mid(i).toAscii().constData()); return false; } i = nextpos; } else if ( src[i] == '>' ) break; else if ( !src[i].isLetterOrNumber() && src[i] != '/' && !word_end ) word_end = i; } QString tagword, tag = src.mid (pos, i - pos); if ( word_end ) tagword = src.mid (pos, word_end - pos).toLower(); else tagword = tag.toLower();//qDebug ("tag: '%s', tagword: '%s'\n", tag.toAscii().constData(), tagword.toAscii().constData()); // <OBJECT type="text/sitemap"> - a topic entry if ( tagword == "object" && tag.indexOf ("text/sitemap", 0, Qt::CaseInsensitive) != -1 ) in_object = true; else if ( tagword == "/object" && in_object ) { // a topic entry closed. Add a tree item if ( !name.isNull() ) { KCHMMainTreeViewItem * item; if ( !root_created ) indent = 0; QString url = urls.join ("|"); // Add item into the tree if ( !indent ) { item = new KCHMMainTreeViewItem (tree, lastchild[indent], name, url, imagenum); } else { if ( !rootentry[indent-1] ) qFatal("CHMFile::ParseAndFillTopicsTree: child entry %d with no root entry!", indent-1); item = new KCHMMainTreeViewItem (rootentry[indent-1], lastchild[indent], name, url, imagenum); } lastchild[indent] = item; if ( indent == 0 || !rootentry[indent] ) { rootentry[indent] = item; root_created = true; if ( asIndex ) rootentry[indent]->setOpen(true); } } else { if ( !urls.isEmpty() ) qDebug ("CHMFile::ParseAndFillTopicsTree: <object> tag with url \"%s\" is parsed, but name is empty.", urls[0].toAscii().constData()); else qDebug ("CHMFile::ParseAndFillTopicsTree: <object> tag is parsed, but both name and url are empty."); } name = QString::null; urls.clear(); in_object = false; imagenum = defaultimagenum; } else if ( tagword == "param" && in_object ) { // <param name="Name" value="First Page"> int offset; // strlen("param ") QString name_pattern = "name=", value_pattern = "value="; QString pname, pvalue; if ( (offset = tag.indexOf (name_pattern, 0, Qt::CaseInsensitive)) == -1 ) qFatal ("CHMFile::ParseAndFillTopicsTree: bad <param> tag '%s': no name=\n", tag.toAscii().constData()); // offset+5 skips 'name=' offset = findStringInQuotes (tag, offset + name_pattern.length(), pname, true, false); pname = pname.toLower(); if ( (offset = tag.indexOf (value_pattern, offset, Qt::CaseInsensitive)) == -1 ) qFatal ("CHMFile::ParseAndFillTopicsTree: bad <param> tag '%s': no value=\n", tag.toAscii().constData()); // offset+6 skips 'value=' findStringInQuotes (tag, offset + value_pattern.length(), pvalue, false, true);//qDebug ("<param>: name '%s', value '%s'", pname.toAscii().constData(), pvalue.toAscii().constData()); if ( pname == "name" ) name = pvalue; else if ( pname == "local" ) urls.push_back (KCHMUrl::makeURLabsoluteIfNeeded (pvalue)); else if ( pname == "see also" && asIndex && name != pvalue ) urls.push_back (":" + pvalue); else if ( pname == "imagenumber" ) { bool bok; int imgnum = pvalue.toInt (&bok); if ( bok && imgnum >= 0 && (unsigned) imgnum < MAX_BUILTIN_ICONS ) imagenum = imgnum; } } else if ( tagword == "ul" ) // increase indent level { // Fix for buggy help files if ( ++indent >= MAX_NEST_DEPTH ) qFatal("CHMFile::ParseAndFillTopicsTree: max nest depth (%d) is reached, error in help file", MAX_NEST_DEPTH); lastchild[indent] = 0; rootentry[indent] = 0; } else if ( tagword == "/ul" ) // decrease indent level { if ( --indent < 0 ) indent = 0; rootentry[indent] = 0; } pos = i; } return true;}bool CHMFile::ParseAndFillTopicsTree(QDomDocument *tree){ return ParseHhcAndFillTree (m_topicsFile, tree, false);}bool CHMFile::ParseAndFillIndex(K3ListView *indexlist){ return ParseHhcAndFillTree (m_indexFile, indexlist, true);}bool CHMFile::SearchWord (const QString& text, bool wholeWords, bool titlesOnly, KCHMSearchProgressResults_t& results, bool phrase_search){ bool partial = false; if ( text.isEmpty() || !m_searchAvailable ) return false; QString searchword = (QString) convertSearchWord (text);#define FTS_HEADER_LEN 0x32 unsigned char header[FTS_HEADER_LEN]; if ( RetrieveObject (&m_chmFIftiMain, header, 0, FTS_HEADER_LEN) == 0 ) return false; unsigned char doc_index_s = header[0x1E], doc_index_r = header[0x1F]; unsigned char code_count_s = header[0x20], code_count_r = header[0x21]; unsigned char loc_codes_s = header[0x22], loc_codes_r = header[0x23]; if(doc_index_s != 2 || code_count_s != 2 || loc_codes_s != 2) { // Don't know how to use values other than 2 yet. Maybe next chmspec. return false; } unsigned char* cursor32 = header + 0x14; u_int32_t node_offset = UINT32ARRAY(cursor32); cursor32 = header + 0x2e; u_int32_t node_len = UINT32ARRAY(cursor32); unsigned char* cursor16 = header + 0x18; u_int16_t tree_depth = UINT16ARRAY(cursor16); unsigned char word_len, pos; QString word; u_int32_t i = sizeof(u_int16_t); u_int16_t free_space; QVector<unsigned char> buffer(node_len); node_offset = GetLeafNodeOffset (searchword, node_offset, node_len, tree_depth); if ( !node_offset ) return false; do { // got a leaf node here. if ( RetrieveObject (&m_chmFIftiMain, buffer.data(), node_offset, node_len) == 0 ) return false; cursor16 = buffer.data() + 6; free_space = UINT16ARRAY(cursor16); i = sizeof(u_int32_t) + sizeof(u_int16_t) + sizeof(u_int16_t); u_int64_t wlc_count, wlc_size; u_int32_t wlc_offset; while (i < node_len - free_space) { word_len = *(buffer.data() + i); pos = *(buffer.data() + i + 1); char *wrd_buf = new char[word_len]; memcpy (wrd_buf, buffer.data() + i + 2, word_len - 1); wrd_buf[word_len - 1] = 0; if ( pos == 0 ) word = wrd_buf; else word = word.mid (0, pos) + wrd_buf; delete[] wrd_buf; i += 2 + word_len; unsigned char title = *(buffer.data() + i - 1); size_t encsz; wlc_count = be_encint (buffer.data() + i, encsz); i += encsz; cursor32 = buffer.data() + i; wlc_offset = UINT32ARRAY(cursor32); i += sizeof(u_int32_t) + sizeof(u_int16_t); wlc_size = be_encint (buffer.data() + i, encsz); i += encsz; cursor32 = buffer.data(); node_offset = UINT32ARRAY(cursor32); if ( !title && titlesOnly )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -