📄 libchmfileimpl.cpp
字号:
QCString LCHMFileImpl::convertSearchWord( const QString & src ){ static const char * searchwordtable[128] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "s", 0, "oe", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "s", 0, "oe", 0, 0, "y", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "a", "a", "a", "a", "a", "a", "ae", "c", "e", "e", "e", "e", "i", "i", "i", "i", "d", "n", "o", "o", "o", "o", "o", 0, "o", "u", "u", "u", "u", "y", "\xDE", "ss", "a", "a", "a", "a", "a", "a", "ae", "c", "e", "e", "e", "e", "i", "i", "i", "i", "o", "n", "o", "o", "o", "o", "o", 0, "o", "u", "u", "u", "u", "y", "\xFE", "y" }; if ( !m_textCodec ) return (QCString) src.lower(); QCString dest = m_textCodec->fromUnicode (src); for ( unsigned int i = 0; i < dest.size(); i++ ) { if ( dest[i] & 0x80 ) { int index = dest[i] & 0x7F; if ( searchwordtable[index] ) dest.replace (i, 1, searchwordtable[index]); else dest.remove (i, 1); } } return dest.lower();}void LCHMFileImpl::getSearchResults( const LCHMSearchProgressResults& tempres, QStringList * results, unsigned int limit_results ){ unsigned char combuf [COMMON_BUF_LEN]; QMap<u_int32_t, u_int32_t> urlsmap; // used to prevent duplicated urls for ( unsigned int i = 0; i < tempres.size(); i++ ) { if ( urlsmap.find (tempres[i].urloff) != urlsmap.end() ) continue; urlsmap[tempres[i].urloff] = 1; if ( RetrieveObject (&m_chmURLSTR, combuf, tempres[i].urloff + 8, COMMON_BUF_LEN - 1) == 0 ) continue; combuf[COMMON_BUF_LEN - 1] = 0; results->push_back( LCHMUrlFactory::makeURLabsoluteIfNeeded( (const char*) combuf ) ); if ( --limit_results == 0 ) break; }}QString LCHMFileImpl::normalizeUrl( const QString & path ) const{ int pos = path.find ('#'); QString fixedpath = pos == -1 ? path : path.left (pos); return LCHMUrlFactory::makeURLabsoluteIfNeeded( fixedpath );}/* * FIXME: <OBJECT type="text/sitemap"><param name="Merge" value="hhaxref.chm::/HHOCX_c.hhc"></OBJECT> * (from htmlhelp.chm)*/bool LCHMFileImpl::parseFileAndFillArray( const QString & file, QT34VECTOR< LCHMParsedEntry > * data, bool asIndex ){ QString src; const int MAX_NEST_DEPTH = 256; if ( !getFileContentAsString( &src, file ) || src.isEmpty() ) return false; KCHMShowWaitCursor wc; /* // Save the index for debugging purposes QFile outfile( "parsed.htm" ); if ( outfile.open( IO_WriteOnly ) ) { QTextStream textstream( &outfile ); textstream << src; outfile.close(); }*/ unsigned int defaultimagenum = asIndex ? LCHMBookIcons::IMAGE_INDEX : LCHMBookIcons::IMAGE_AUTO; int pos = 0, indent = 0, root_indent_offset = 0; bool in_object = false, root_indent_offset_set = false; LCHMParsedEntry entry; entry.imageid = defaultimagenum; // Split the HHC file by HTML tags int stringlen = src.length(); while ( pos < stringlen && (pos = src.find ('<', 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.find (src[i], i+1); if ( nextpos == -1 && (nextpos = src.find ('>', i+1)) == -1 ) { qWarning ("LCHMFileImpl::ParseHhcAndFillTree: corrupted TOC: %s", src.mid(i).ascii()); 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).lower(); else tagword = tag.lower(); //qDebug ("tag: '%s', tagword: '%s'\n", tag.ascii(), tagword.ascii()); // <OBJECT type="text/sitemap"> - a topic entry if ( tagword == "object" && tag.find ("text/sitemap", 0, false) != -1 ) in_object = true; else if ( tagword == "/object" && in_object ) { // a topic entry closed. Add a tree item if ( entry.name ) { if ( !root_indent_offset_set ) { root_indent_offset_set = true; root_indent_offset = indent; if ( root_indent_offset > 1 ) qWarning("CHM has improper index; root indent offset is %d", root_indent_offset); } int real_indent = indent - root_indent_offset; entry.indent = real_indent; data->push_back( entry ); } else { if ( !entry.urls.isEmpty() ) qDebug ("LCHMFileImpl::ParseAndFillTopicsTree: <object> tag with url \"%s\" is parsed, but name is empty.", entry.urls[0].ascii()); else qDebug ("LCHMFileImpl::ParseAndFillTopicsTree: <object> tag is parsed, but both name and url are empty."); } entry.name = QString::null; entry.urls.clear(); entry.imageid = defaultimagenum; in_object = false; } 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.find (name_pattern, 0, FALSE)) == -1 ) qFatal ("LCHMFileImpl::ParseAndFillTopicsTree: bad <param> tag '%s': no name=\n", tag.ascii()); // offset+5 skips 'name=' offset = findStringInQuotes (tag, offset + name_pattern.length(), pname, TRUE, FALSE); pname = pname.lower(); if ( (offset = tag.find (value_pattern, offset, FALSE)) == -1 ) qFatal ("LCHMFileImpl::ParseAndFillTopicsTree: bad <param> tag '%s': no value=\n", tag.ascii()); // offset+6 skips 'value=' findStringInQuotes (tag, offset + value_pattern.length(), pvalue, FALSE, TRUE); //qDebug ("<param>: name '%s', value '%s'", pname.ascii(), pvalue.ascii()); if ( pname == "name" ) { // Some help files contain duplicate names, where the second name is empty. Work it around by keeping the first one if ( !pvalue.isEmpty() ) entry.name = pvalue; } else if ( pname == "local" ) { // Check for URL duplication QString url = LCHMUrlFactory::makeURLabsoluteIfNeeded( pvalue ); if ( entry.urls.find( url ) == entry.urls.end() ) entry.urls.push_back( url ); } else if ( pname == "see also" && asIndex && entry.name != pvalue ) entry.urls.push_back (":" + pvalue); else if ( pname == "imagenumber" ) { bool bok; int imgnum = pvalue.toInt (&bok); if ( bok && imgnum >= 0 && imgnum < LCHMBookIcons::MAX_BUILTIN_ICONS ) entry.imageid = imgnum; } } else if ( tagword == "ul" ) // increase indent level { // Fix for buggy help files if ( ++indent >= MAX_NEST_DEPTH ) qFatal("LCHMFileImpl::ParseAndFillTopicsTree: max nest depth (%d) is reached, error in help file", MAX_NEST_DEPTH); // This intended to fix <ul><ul>, which was seen in some buggy chm files, // and brokes rootentry[indent-1] check } else if ( tagword == "/ul" ) // decrease indent level { if ( --indent < root_indent_offset ) indent = root_indent_offset; DEBUGPARSER(("</ul>: new intent is %d\n", indent - root_indent_offset)); } pos = i; } return true;}bool LCHMFileImpl::getFileContentAsBinary( QByteArray * data, const QString & url ) const{ chmUnitInfo ui; if( !ResolveObject( url, &ui ) ) return false; data->resize( ui.length ); if ( RetrieveObject( &ui, (unsigned char*) data->data(), 0, ui.length ) ) return true; else return false;} bool LCHMFileImpl::getFileContentAsString( QString * str, const QString & url, bool internal_encoding ){ QByteArray buf; if ( getFileContentAsBinary( &buf, url ) ) { unsigned int length = buf.size(); if ( length > 0 ) { buf.resize( length + 1 ); buf [length] = '\0'; *str = internal_encoding ? (QString)((const char*) buf) : encodeWithCurrentCodec((const char*) buf); return true; } } return false;}QString LCHMFileImpl::getTopicByUrl( const QString & url ) const{ QMap< QString, QString >::const_iterator it = m_url2topics.find( url ); if ( it == m_url2topics.end() ) return QString::null; return it.data();}static int chm_enumerator_callback( struct chmFile*, struct chmUnitInfo *ui, void *context ){ ((QStringList*) context)->push_back( ui->path ); return CHM_ENUMERATOR_CONTINUE;}bool LCHMFileImpl::enumerateFiles( QStringList * files ){ files->clear(); return chm_enumerate( m_chmFile, CHM_ENUMERATE_ALL, chm_enumerator_callback, files );}const QPixmap * LCHMFileImpl::getBookIconPixmap( unsigned int imagenum ){ return m_imagesKeeper.getImage( imagenum );}bool LCHMFileImpl::setCurrentEncoding( const LCHMTextEncoding * encoding ){ m_currentEncoding = encoding; return changeFileEncoding( encoding->qtcodec );}bool LCHMFileImpl::guessTextEncoding( ){ const LCHMTextEncoding * enc = 0; if ( !m_detectedLCID || (enc = lookupByLCID (m_detectedLCID)) == 0 ) qFatal ("Could not detect text encoding by LCID"); if ( changeFileEncoding (enc->qtcodec) ) { m_currentEncoding = enc; return true; } return false;}bool LCHMFileImpl::changeFileEncoding( const char *qtencoding ){ // Encoding could be either simple Qt codepage, or set like CP1251/KOI8, which allows to // set up encodings separately for text (first) and internal files (second) const char * p = strchr( qtencoding, '/' ); if ( p ) { char buf[128]; // much bigger that any encoding possible. No DoS; all encodings are hardcoded. strcpy( buf, qtencoding ); buf[p - qtencoding] = '\0'; m_textCodec = QTextCodec::codecForName( buf ); if ( !m_textCodec ) { qWarning( "Could not set up Text Codec for encoding '%s'", buf ); return false; } m_textCodecForSpecialFiles = QTextCodec::codecForName( p + 1 ); if ( !m_textCodecForSpecialFiles ) { qWarning( "Could not set up Text Codec for encoding '%s'", p + 1 ); return false; } } else { m_textCodecForSpecialFiles = m_textCodec = QTextCodec::codecForName (qtencoding); if ( !m_textCodec ) { qWarning( "Could not set up Text Codec for encoding '%s'", qtencoding ); return false; } } m_entityDecodeMap.clear(); return true;}void LCHMFileImpl::fillTopicsUrlMap(){ if ( !m_lookupTablesValid ) return; // Read those tables QByteArray topics( m_chmTOPICS.length ), urltbl( m_chmURLTBL.length ), urlstr( m_chmURLSTR.length ), strings( m_chmSTRINGS.length ); if ( !RetrieveObject( &m_chmTOPICS, (unsigned char*) topics.data(), 0, m_chmTOPICS.length ) || !RetrieveObject( &m_chmURLTBL, (unsigned char*) urltbl.data(), 0, m_chmURLTBL.length ) || !RetrieveObject( &m_chmURLSTR, (unsigned char*) urlstr.data(), 0, m_chmURLSTR.length ) || !RetrieveObject( &m_chmSTRINGS, (unsigned char*) strings.data(), 0, m_chmSTRINGS.length ) ) return; for ( unsigned int i = 0; i < m_chmTOPICS.length; i += TOPICS_ENTRY_LEN ) { u_int32_t off_title = get_int32_le( (u_int32_t *)(topics.data() + i + 4) ); u_int32_t off_url = get_int32_le( (u_int32_t *)(topics.data() + i + 8) ); off_url = get_int32_le( (u_int32_t *)( urltbl.data() + off_url + 8) ) + 8; QString url = LCHMUrlFactory::makeURLabsoluteIfNeeded( (const char*) urlstr.data() + off_url ); if ( off_title < strings.size() ) m_url2topics[url] = encodeWithCurrentCodec ( (const char*) strings.data() + off_title ); else m_url2topics[url] = "Untitled"; }}bool LCHMFileImpl::getFileSize(unsigned int * size, const QString & url){ chmUnitInfo ui; if( !ResolveObject( url, &ui ) ) return false; *size = ui.length; return true;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -