summaryrefslogtreecommitdiffstats
path: root/parts/documentation/protocols
diff options
context:
space:
mode:
authortoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
committertoma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2009-11-25 17:56:58 +0000
commit114a878c64ce6f8223cfd22d76a20eb16d177e5e (patch)
treeacaf47eb0fa12142d3896416a69e74cbf5a72242 /parts/documentation/protocols
downloadtdevelop-114a878c64ce6f8223cfd22d76a20eb16d177e5e.tar.gz
tdevelop-114a878c64ce6f8223cfd22d76a20eb16d177e5e.zip
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923 git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdevelop@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'parts/documentation/protocols')
-rw-r--r--parts/documentation/protocols/Makefile.am4
-rw-r--r--parts/documentation/protocols/chm/Makefile.am21
-rw-r--r--parts/documentation/protocols/chm/chm.cpp362
-rw-r--r--parts/documentation/protocols/chm/chm.h47
-rw-r--r--parts/documentation/protocols/chm/chm.protocol36
-rw-r--r--parts/documentation/protocols/chm/chmfile.cpp197
-rw-r--r--parts/documentation/protocols/chm/chmfile.h53
-rw-r--r--parts/documentation/protocols/chm/decompress.cpp796
-rw-r--r--parts/documentation/protocols/chm/decompress.h43
-rw-r--r--parts/documentation/protocols/chm/kchmpart.cpp123
-rw-r--r--parts/documentation/protocols/chm/kchmpart.desktop46
-rw-r--r--parts/documentation/protocols/chm/kchmpart.h82
12 files changed, 1810 insertions, 0 deletions
diff --git a/parts/documentation/protocols/Makefile.am b/parts/documentation/protocols/Makefile.am
new file mode 100644
index 00000000..ef837725
--- /dev/null
+++ b/parts/documentation/protocols/Makefile.am
@@ -0,0 +1,4 @@
+INCLUDES = -I$(top_srcdir)/lib/interfaces -I$(top_srcdir)/lib/util $(all_includes)
+METASOURCES = AUTO
+
+SUBDIRS = chm
diff --git a/parts/documentation/protocols/chm/Makefile.am b/parts/documentation/protocols/chm/Makefile.am
new file mode 100644
index 00000000..59d02cfd
--- /dev/null
+++ b/parts/documentation/protocols/chm/Makefile.am
@@ -0,0 +1,21 @@
+## Makefile.am of kdebase/kioslave/chm
+
+INCLUDES = -I$(top_srcdir)/lib/widgets $(all_includes)
+
+kde_module_LTLIBRARIES = kio_chm.la libkchmpart.la
+
+kio_chm_la_SOURCES = decompress.cpp chmfile.cpp chm.cpp
+kio_chm_la_LIBADD = $(LIB_KIO)
+kio_chm_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+
+libkchmpart_la_SOURCES = kchmpart.cpp
+libkchmpart_la_LIBADD = -lkhtml $(LIB_KPARTS) $(top_builddir)/lib/widgets/libkdevwidgets.la
+libkchmpart_la_LDFLAGS = $(all_libraries) $(KDE_PLUGIN)
+
+noinst_HEADERS = chm.h chmfile.h decompress.h kchmpart.h
+
+kdelnk_DATA = chm.protocol kchmpart.desktop
+kdelnkdir = $(kde_servicesdir)
+
+METASOURCES = AUTO
+
diff --git a/parts/documentation/protocols/chm/chm.cpp b/parts/documentation/protocols/chm/chm.cpp
new file mode 100644
index 00000000..1383d2b6
--- /dev/null
+++ b/parts/documentation/protocols/chm/chm.cpp
@@ -0,0 +1,362 @@
+/* This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <qcstring.h>
+#include <qbitarray.h>
+#include <qfile.h>
+#include <qregexp.h>
+#include <stack>
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+
+#include <kapplication.h>
+#include <kdebug.h>
+#include <kinstance.h>
+#include <kglobal.h>
+#include <kurl.h>
+#include <kmimemagic.h>
+#include <ktempfile.h>
+
+#include "chm.h"
+
+
+using namespace KIO;
+
+extern "C"
+{
+ int kdemain( int argc, char **argv )
+ {
+ KInstance instance( "kio_chm" );
+
+ kdDebug() << "*** Starting kio_chm " << endl;
+
+ if (argc != 4) {
+ kdDebug() << "Usage: kio_chm protocol domain-socket1 domain-socket2" << endl;
+ exit(-1);
+ }
+
+ ChmProtocol slave(argv[2], argv[3]);
+ slave.dispatchLoop();
+
+ kdDebug() << "*** kio_chm Done" << endl;
+ return 0;
+ }
+}
+
+ChmProtocol::ChmProtocol(const QCString &pool_socket, const QCString &app_socket)
+: SlaveBase("kio_chm", pool_socket, app_socket)
+{
+ kdDebug() << "ChmProtocol::ChmProtocol()" << endl;
+}
+/* ---------------------------------------------------------------------------------- */
+
+
+ChmProtocol::~ChmProtocol()
+{
+ kdDebug() << "ChmProtocol::~ChmProtocol()" << endl;
+}
+
+
+/* ---------------------------------------------------------------------------------- */
+void ChmProtocol::get( const KURL& url )
+{
+ /** When :catalog is appended to the end, a plain-text representation of the catalog
+ * is given out where each entry consists of four lines, an integer representing the parent
+ * of the node, an integer representing a node's ID, the Title of the Node, and it's hyperlink.
+ * When :contents is appended, all contained htm- and html-files will be printed, each in a line.
+ */
+ kdDebug() << "kio_chm::get(const KURL& url) " << url.path() << endl;
+
+ bool catalog = false;
+ bool contents = false;
+ QString bigpath = url.path();
+
+ if(bigpath.endsWith(":catalog")) {
+ catalog = true;
+ int len = QString(":catalog").length();
+ bigpath.remove(bigpath.length() - len, len); ///strip :catalog from the end
+ }
+
+ if(bigpath.endsWith(":contents")) {
+ contents = true;
+ int len = QString(":contents").length();
+ bigpath.remove(bigpath.length() - len, len); ///strip :catalog from the end
+ }
+
+ QString path;
+ if ( !checkNewFile( bigpath, path ) ) {
+ error( KIO::ERR_DOES_NOT_EXIST, url.prettyURL() );
+ return;
+ }
+
+
+ if (m_dirMap.find(path) == m_dirMap.end()) {
+ error( KIO::ERR_DOES_NOT_EXIST, url.prettyURL() );
+ return;
+ }
+
+ QByteArray theData;
+
+ //init..
+ //added by lucida lucida@users.sf.net
+ QString fname = QString();
+ QString chmpath = QString();
+ KTempFile f("",".html");
+ fname = f.name();
+ QTextStream *t = f.textStream();
+ QString firstPage = QString("");
+ QString m_strIndex = QString("");
+ QString tmpstr = QString("");
+ bool m_bIndex = 0;
+
+
+ if(contents) {
+ QString output;
+ KURL u = url;
+
+ ChmDirectoryMap::Iterator it;
+ for ( it = m_dirMap.begin(); it != m_dirMap.end(); ++it) {
+ u.setPath(bigpath);
+ u.addPath(it.key());
+ output += u.prettyURL() + "\n";
+ }
+
+ data(output.local8Bit());
+ processedSize(output.length());
+ finished();
+ return;
+ }
+
+
+ //try get some page to display, if the chm missing index
+ ChmDirectoryMap::Iterator it;
+ for ( it = m_dirMap.begin(); it != m_dirMap.end(); ++it) {
+ tmpstr.sprintf("%s", it.key().latin1());
+ if ((m_strIndex == "") &&
+ (tmpstr.endsWith(".htm") || tmpstr.endsWith(".html")))
+ m_strIndex = tmpstr;
+ if ((tmpstr == "/index.htm") || (tmpstr == "/index.html")) {
+ m_strIndex = tmpstr;
+ break;
+ }
+ }
+ m_strIndex.remove(0,1);
+
+
+ if (path == "/" || catalog) {
+ bool htmlOutput = !catalog;
+ int offset = m_dirMap["/@contents"].offset;
+ int length = m_dirMap["/@contents"].length;
+ theData.setRawData(&m_contents[offset], length);
+ QString s(theData);
+ QString output;
+
+ QRegExp object("<OBJECT type=\"text/sitemap\">(.*)</OBJECT>", false);
+ object.setMinimal(true);
+
+ QRegExp nameParam("<param name=\"Name\" value=\"(.*)\">", false);
+ nameParam.setMinimal(true);
+
+ QRegExp localParam("<param name=\"Local\" value=\"(.*)\">", false);
+ localParam.setMinimal(true);
+
+ QRegExp mergeParam("<param name=\"Merge\" value=\"(.*)\">", false);
+ mergeParam.setMinimal(true);
+
+ std::stack<int> parents;
+ int counter = 1;
+ int current = 0;
+ int old = 0, pos = 0;
+ parents.push(0);
+ while ((pos = s.find(object, pos)) != -1) {
+ if(htmlOutput) output += s.mid(old, pos - old);
+ if(catalog) {
+ QRegExp ex("<UL>|</UL>", false); ex.setMinimal(true);
+ QString ms = s.mid(old, pos - old);
+ int pos = 0;
+ while( (pos = ms.find(ex, pos)) != -1) {
+ if(ms.mid(pos, 4) == "<UL>") {
+ parents.push(current);
+ } else{
+ if(parents.empty()){
+ }else{
+ current = parents.top();
+ parents.pop();
+ }
+ }
+ pos++;
+ }
+ }
+ pos += object.matchedLength();
+ old = pos;
+ QString obj = object.cap(1);
+ QString name, local;
+ if (obj.find(nameParam) != -1) {
+ name = nameParam.cap(1);
+ if (obj.find(localParam) != -1) {
+ local = localParam.cap(1);
+ //output += "<a href=\"" + local + "\">" + name + "</a>";
+ //added by lucida lucida@users.sf.net
+ if (local != "" && local != "/") {
+ if(!catalog) {
+ output += "<a target=\"browse\" href=\"" + url.url() + local + "\">" + name + "</a>";
+ }else{
+ current = counter;
+ ++counter;
+ KURL u = url;
+ u.setPath(bigpath + local);
+ QString str;
+ output += str.sprintf("%i\n%i\n", parents.top(), current);
+ output += name + "\n" + u.prettyURL() + "\n";
+ }
+ m_bIndex = 1;
+ if (firstPage == "") firstPage = url.url()+QString::fromLocal8Bit(local.latin1());
+ }
+ else
+ if(htmlOutput) output += name;
+ } else {
+ if(htmlOutput) output += name;
+ }
+ }
+ if (obj.find(mergeParam) != -1 && htmlOutput) {
+ QString link = mergeParam.cap(1);
+ QString href = link.left(link.find("::"));
+ QString path = m_chmFile.left(m_chmFile.findRev("/") + 1);
+ //output += " (<a href=\"" + path + href + "\">link</a>)";
+ m_bIndex = 1;
+ output += " (<a target=\"browse\" href=\"" + url.url() + path + href + "\">link</a>)";
+ if (firstPage == "") firstPage = url.url()+QString::fromLocal8Bit(local.latin1());
+ }
+ }
+ if(htmlOutput) output += s.mid(old);
+
+ //set left pane
+ //added by lucida, lucida@users.sf.net
+ QString lframe = QString("</HEAD><FRAMESET COLS=\"25%,*\">\n");
+ lframe += "<FRAME NAME=\"index\" src=\"file:"+ fname+"\"" + " marginwidth=\"0\"></FRAME>\n";
+ if (!m_bIndex) {
+ lframe = "</HEAD><FRAMESET>";
+ firstPage = url.url() + QString::fromLocal8Bit(m_strIndex.latin1());
+ }
+ theData.resetRawData(&m_contents[offset], length);
+ //KMimeMagicResult * result = KMimeMagic::self()->findBufferFileType( output, path );
+ //kdDebug() << "Emitting mimetype " << result->mimeType() << endl;
+ //mimeType( result->mimeType() );
+/* QCString output1 = (QCString)(output.latin1());
+ data(output1);
+ processedSize(output1.length());*/
+
+ //construct the frame
+ //added by lucida lucida@users.sf.net
+ QString framestr = QString("<HTML><HEAD>\n");
+ framestr += lframe;
+ framestr += "<FRAME NAME=\"browse\" src=\"" + firstPage + "\">\n";
+ framestr += "</FRAME>\n";
+ framestr += "</FRAMESET></HTML>";
+ //write index file
+ //added by lucida lucida@users.sf.net
+ *t << QString::fromLocal8Bit(output.latin1()) << endl;
+
+ if(catalog) {
+ data(output.local8Bit());
+ processedSize(output.length());
+ }else{
+ data(framestr.local8Bit());
+ processedSize(framestr.length());
+ }
+ } else {
+ int offset = m_dirMap[path].offset;
+ int length = m_dirMap[path].length;
+ totalSize(length);
+ theData.setRawData(&m_contents[offset], length);
+
+ KMimeMagicResult * result = KMimeMagic::self()->findBufferFileType( theData, path );
+ kdDebug() << "Emitting mimetype " << result->mimeType() << endl;
+ mimeType( result->mimeType() );
+ data(theData);
+ theData.resetRawData(&m_contents[offset], length);
+ processedSize(length);
+ }
+
+ finished();
+}
+
+/* --------------------------------------------------------------------------- */
+bool ChmProtocol::checkNewFile( QString fullPath, QString& path )
+{
+ //kdDebug() << "ChmProtocol::checkNewFile " << fullPath << endl;
+
+ fullPath = fullPath.replace(QRegExp("::"), "");
+
+ // Are we already looking at that file ?
+ if ( !m_chmFile.isEmpty() && fullPath.startsWith(m_chmFile) )
+ {
+ path = fullPath.mid(m_chmFile.length()).lower();
+ return true;
+ }
+
+ kdDebug() << "Need to open a new file" << endl;
+
+ m_chmFile = "";
+
+ // Find where the chm file is in the full path
+ int pos = 0;
+ QString chmFile;
+ path = "";
+
+ int len = fullPath.length();
+ if ( len != 0 && fullPath[ len - 1 ] != '/' )
+ fullPath += '/';
+
+ //kdDebug() << "the full path is " << fullPath << endl;
+ while ( (pos=fullPath.find( '/', pos+1 )) != -1 )
+ {
+ QString tryPath = fullPath.left( pos );
+ //kdDebug() << fullPath << " trying " << tryPath << endl;
+ struct stat statbuf;
+ if ( ::stat( QFile::encodeName(tryPath), &statbuf ) == 0 && !S_ISDIR(statbuf.st_mode) )
+ {
+ chmFile = tryPath;
+ path = fullPath.mid( pos ).lower();
+ kdDebug() << "fullPath=" << fullPath << " path=" << path << endl;
+ len = path.length();
+ if ( len > 2 )
+ {
+ if ( path[ len - 1 ] == '/' )
+ path.truncate( len - 1 );
+ }
+ else
+ {
+ path = QString::fromLatin1("/");
+ }
+ kdDebug() << "Found. chmFile=" << chmFile << " path=" << path << endl;
+ break;
+ }
+ }
+ if ( chmFile.isEmpty() )
+ {
+ kdDebug() << "ChmProtocol::checkNewFile: not found" << endl;
+ return false;
+ }
+
+ m_chmFile = chmFile;
+
+ // Open new file
+ //kdDebug() << "Opening Chm file on " << chmFile << endl;
+ return m_chm.read(chmFile, m_dirMap, m_contents);
+}
diff --git a/parts/documentation/protocols/chm/chm.h b/parts/documentation/protocols/chm/chm.h
new file mode 100644
index 00000000..92044173
--- /dev/null
+++ b/parts/documentation/protocols/chm/chm.h
@@ -0,0 +1,47 @@
+/* This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __chm_h__
+#define __chm_h__
+
+#include <qstring.h>
+#include <qcstring.h>
+#include <kurl.h>
+#include <kio/global.h>
+#include <kio/slavebase.h>
+#include "chmfile.h"
+
+class QCString;
+
+class ChmProtocol : public KIO::SlaveBase
+{
+public:
+ ChmProtocol( const QCString&, const QCString& );
+ ~ChmProtocol();
+
+ void get( const KURL& );
+
+private:
+ bool checkNewFile( QString, QString& );
+ ChmDirectoryMap m_dirMap;
+ QByteArray m_contents;
+ QString m_chmFile;
+ Chm m_chm;
+};
+
+
+#endif // __chm_h__
+
diff --git a/parts/documentation/protocols/chm/chm.protocol b/parts/documentation/protocols/chm/chm.protocol
new file mode 100644
index 00000000..90daa4c5
--- /dev/null
+++ b/parts/documentation/protocols/chm/chm.protocol
@@ -0,0 +1,36 @@
+[Protocol]
+exec=kio_chm
+protocol=ms-its
+input=none
+output=filesystem
+reading=true
+defaultMimetype=text/html
+Description=A kioslave for displaying WinHelp files
+Description[ca]=Un kioslave per a mostrar fitxers WinHelp
+Description[da]=En kioslave til visning af Windows hjælpefiler
+Description[de]=Ein Ein-/Ausgabemodul zur Anzeige von WinHelp-Dateien
+Description[el]=Ένας υπηρέτης kio για εμφάνιση αρχείων WinHelp
+Description[es]=Un kioslave para mostrar archivos WinHelp
+Description[et]=WinHelp-failide kuvamise IO-moodul
+Description[eu]=WinHelp fitxategiak bistaratzeko kioslave bat
+Description[fa]=یک kioslave برای نمایش پرونده‌های WinHelp
+Description[fr]=Un esclave d'E/S (kioslave) pour l'affichage des fichiers WinHelp
+Description[gl]=Un kioslave para mostrar ficheiros WinHelp
+Description[hu]=KDE-protokoll WinHelp-fájlok megjelenítéséhez
+Description[it]=Un kioslave per mostrare i file WinHelp
+Description[ja]=WinHelp を表示するための kioslave
+Description[nds]=En In-/Utgaavmoduul för't Wiesen vun "WinHelp"-Dateien
+Description[ne]=WinHelp फाइलहरूका लागि किवस्लेभ
+Description[nl]=Een kioslave voor het weergeven van WinHelp-bestanden
+Description[pl]=kioslave do pokazywania plików WinHelp
+Description[pt]=A 'kioslave' para mostrar ficheiros WinHelp
+Description[pt_BR]=Um kioslave para exibir arquivos WinHelp
+Description[ru]=Обработчик ввода-вывода для файлов WinHelp
+Description[sk]=kioslave pre zobrazenie WinHelp súborov
+Description[sr]=KIOSlave за приказ WinHelp фајлова
+Description[sr@Latn]=KIOSlave za prikaz WinHelp fajlova
+Description[sv]=En I/O-slav för att visa WinHelp-filer
+Description[tr]=WinHelp dosyalarını görüntülemek için bir kioslave
+Description[zh_CN]=显示 WinHelp 文件的 kioslave
+Description[zh_TW]=顯示 WinHelp 檔案的 kioslave
+Icon=help
diff --git a/parts/documentation/protocols/chm/chmfile.cpp b/parts/documentation/protocols/chm/chmfile.cpp
new file mode 100644
index 00000000..f69d354a
--- /dev/null
+++ b/parts/documentation/protocols/chm/chmfile.cpp
@@ -0,0 +1,197 @@
+/* This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <qfile.h>
+#include "chmfile.h"
+#include "decompress.h"
+
+uint Chm::getEncInt(QFile& f, uint &value) const
+{
+ int c;
+ uint result = 0;
+ ulong count = 0;
+
+ do
+ {
+ c = f.getch();
+ result <<= 7;
+ result |= (c & 0x7F);
+ count++;
+ } while (c & 0x80);
+
+ value = result;
+ return count;
+}
+
+uint Chm::getName(QFile& f, QString& name) const
+{
+ int len = f.getch();
+ char *buf = new char[len];
+ f.readBlock(buf, len);
+ name = QString::fromUtf8(buf, len);
+ if (name.startsWith("/"))
+ name = name.lower();
+ delete [] buf;
+ return len + 1;
+}
+
+uint Chm::getIntel32(QFile& f) const
+{
+ uint value = f.getch() | f.getch() << 8 | f.getch() << 16 | f.getch() << 24;
+ return value;
+}
+
+uint Chm::getIntel64(QFile& f) const
+{
+ uint value = getIntel32(f);
+ f.at(f.at() + 4);
+ return value;
+}
+
+bool Chm::getChunk(QFile& f, uint chunkSize, ChmDirectoryMap& directoryMap) const
+{
+ char tag[4];
+ if (f.readBlock(tag, 4) != 4) return false;
+
+ if (!qstrncmp(tag, "PMGL", 4))
+ {
+ uint quickref_length = getIntel32(f);
+ f.at(f.at() + 12);
+
+ uint pos = 20;
+ while (pos < chunkSize - quickref_length)
+ {
+ uint section, offset, length;
+ QString name;
+ pos += getName(f, name);
+ pos += getEncInt(f, section);
+ pos += getEncInt(f, offset);
+ pos += getEncInt(f, length);
+ directoryMap[name] = ChmDirTableEntry(section, offset, length);
+ if (name.endsWith(".hhc"))
+ directoryMap["/@contents"] = ChmDirTableEntry(section, offset, length);
+ }
+
+ return (f.at(f.at() + quickref_length));
+ }
+ else if (!qstrncmp(tag, "PMGI", 4))
+ {
+ // evaluation of the index chunk is not yet implemented => skip it
+ return f.at(f.at() + chunkSize - 4);
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool Chm::read(const QString& fileSpec, ChmDirectoryMap& dirMap, QByteArray& contents) const
+{
+ QFile f(fileSpec);
+ if (!f.open(IO_ReadOnly)) return false;
+
+ // read CHM file header
+ char tag[4];
+ if (f.readBlock(tag, 4) != 4 || qstrncmp(tag, "ITSF", 4)) return false;
+ uint chm_version = getIntel32(f);
+ if (!f.at(f.at() + 0x30)) return false;
+
+ // read header section table
+ uint section_0_offset = getIntel64(f);
+ uint section_0_length = getIntel64(f);
+ uint section_1_offset = getIntel64(f);
+ uint section_1_length = getIntel64(f);
+
+ uint contentStart = 0;
+ if (chm_version >= 3) contentStart = getIntel32(f);
+
+ // read directory header
+ if (!f.at(section_1_offset)) return false;
+ if (f.readBlock(tag, 4) != 4 || qstrncmp(tag, "ITSP", 4)) return false;
+ if (!f.at(f.at() + 12)) return false;
+ uint directory_chunk_size = getIntel32(f);
+ if (!f.at(f.at() + 24)) return false;
+ uint num_directory_chunks = getIntel32(f);
+ if (!f.at(f.at() + 36)) return false;
+
+ // read directory table
+ for (uint i = 0; i < num_directory_chunks; i++)
+ if (!getChunk(f, directory_chunk_size, dirMap)) return false;
+
+ // current position is start of content area
+ if (chm_version < 3) contentStart = f.at();
+
+ // read reset table
+ if (!f.at(contentStart)) return false;
+ uint resetTableOffset =
+ dirMap["::DataSpace/Storage/MSCompressed/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTable"].offset;
+ if (!f.at(f.at() + resetTableOffset + 4)) return false;
+ uint numResetTableEntries = getIntel32(f);
+ if (!f.at(f.at() + 8)) return false;
+ uint uncompressedLength = getIntel64(f);
+ uint compressedLength = getIntel64(f);
+ uint blockSize = getIntel64(f);
+ uint *resetTable = new uint[numResetTableEntries + 1];
+
+ for (uint i = 0; i < numResetTableEntries; i++)
+ resetTable[i] = getIntel64(f);
+
+ resetTable[numResetTableEntries] = compressedLength;
+
+ // read compressed contents
+ if (!f.at(contentStart)) return false;
+ uint contentsOffset = dirMap["::DataSpace/Storage/MSCompressed/Content"].offset;
+ if (!f.at(f.at() + contentsOffset)) return false;
+ char *compressedContents = new char[compressedLength];
+ if ((uint)f.readBlock(compressedContents, compressedLength) != compressedLength) return false;
+
+ f.close();
+
+ // allocate buffer for uncompressed contents
+ char *uncompressedContents = new char[uncompressedLength];
+
+ // get window size
+ uint window = 1;
+ uint tmp = blockSize;
+ while (tmp >>= 1) window++;
+
+ // decompress
+ uint outlen = uncompressedLength;
+ int res = 1;
+
+ for (uint i = 0; i < numResetTableEntries; i++)
+ {
+ if (!(i & 1)) LZXinit(window);
+
+ uint inlen = resetTable[i+1] - resetTable[i];
+ res = LZXdecompress((uchar*)&compressedContents[resetTable[i]],
+ inlen,
+ (uchar*)uncompressedContents + i * blockSize,
+ (outlen < blockSize) ? outlen : blockSize);
+ if (res) break;
+ outlen -= blockSize;
+ }
+
+ delete [] resetTable;
+ delete [] compressedContents;
+
+ if (res == 0)
+ contents.duplicate(uncompressedContents, uncompressedLength);
+
+ delete [] uncompressedContents;
+
+ return (res == 0);
+}
diff --git a/parts/documentation/protocols/chm/chmfile.h b/parts/documentation/protocols/chm/chmfile.h
new file mode 100644
index 00000000..0040c135
--- /dev/null
+++ b/parts/documentation/protocols/chm/chmfile.h
@@ -0,0 +1,53 @@
+/* This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __chmfile_h__
+#define __chmfile_h__
+
+#include <cstdio>
+#include <qmap.h>
+#include <qstring.h>
+
+class QFile;
+
+struct ChmDirTableEntry
+{
+ ChmDirTableEntry() : section(0), offset(0), length(0) {}
+ ChmDirTableEntry( uint s, uint o, uint l )
+ : section(s), offset(o), length(l) {}
+
+ uint section;
+ uint offset;
+ uint length;
+};
+
+typedef QMap<QString, ChmDirTableEntry> ChmDirectoryMap;
+
+class Chm
+{
+public:
+ bool read( const QString&, ChmDirectoryMap&, QByteArray& ) const;
+
+private:
+ bool getChunk( QFile&, uint, ChmDirectoryMap& ) const;
+ uint getEncInt( QFile&, uint& ) const;
+ uint getName( QFile&, QString& ) const;
+ uint getIntel32( QFile& ) const;
+ uint getIntel64( QFile& ) const;
+};
+
+#endif // __chmfile_h__
+
diff --git a/parts/documentation/protocols/chm/decompress.cpp b/parts/documentation/protocols/chm/decompress.cpp
new file mode 100644
index 00000000..0356d86e
--- /dev/null
+++ b/parts/documentation/protocols/chm/decompress.cpp
@@ -0,0 +1,796 @@
+/* Most of this file is taken from:
+ cabextract 0.5 - a program to extract Microsoft Cabinet files
+ (C) 2000-2001 Stuart Caie <kyzer@4u.net>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "decompress.h"
+
+int make_decode_table(ULONG nsyms, ULONG nbits, UBYTE *length, UWORD *table);
+int lzx_read_lens(UBYTE *lens, ULONG first, ULONG last, lzx_bits *lb);
+
+
+/*--------------------------------------------------------------------------*/
+/* our archiver information / state */
+
+/* LZX stuff */
+
+/* some constants defined by the LZX specification */
+#define LZX_MIN_MATCH (2)
+#define LZX_MAX_MATCH (257)
+#define LZX_NUM_CHARS (256)
+#define LZX_BLOCKTYPE_INVALID (0) /* also blocktypes 4-7 invalid */
+#define LZX_BLOCKTYPE_VERBATIM (1)
+#define LZX_BLOCKTYPE_ALIGNED (2)
+#define LZX_BLOCKTYPE_UNCOMPRESSED (3)
+#define LZX_PRETREE_NUM_ELEMENTS (20)
+#define LZX_ALIGNED_NUM_ELEMENTS (8) /* aligned offset tree #elements */
+#define LZX_NUM_PRIMARY_LENGTHS (7) /* this one missing from spec! */
+#define LZX_NUM_SECONDARY_LENGTHS (249) /* length tree #elements */
+
+/* LZX huffman defines: tweak tablebits as desired */
+#define LZX_PRETREE_MAXSYMBOLS (LZX_PRETREE_NUM_ELEMENTS)
+#define LZX_PRETREE_TABLEBITS (6)
+#define LZX_MAINTREE_MAXSYMBOLS (LZX_NUM_CHARS + 50*8)
+#define LZX_MAINTREE_TABLEBITS (12)
+#define LZX_LENGTH_MAXSYMBOLS (LZX_NUM_SECONDARY_LENGTHS+1)
+#define LZX_LENGTH_TABLEBITS (12)
+#define LZX_ALIGNED_MAXSYMBOLS (LZX_ALIGNED_NUM_ELEMENTS)
+#define LZX_ALIGNED_TABLEBITS (7)
+
+#define LZX_LENTABLE_SAFETY (64) /* we allow length table decoding overruns */
+
+#define LZX_DECLARE_TABLE(tbl) \
+ UWORD tbl##_table[(1<<LZX_##tbl##_TABLEBITS) + (LZX_##tbl##_MAXSYMBOLS<<1)];\
+ UBYTE tbl##_len [LZX_##tbl##_MAXSYMBOLS + LZX_LENTABLE_SAFETY]
+
+struct LZXstate
+{
+ UBYTE *window; /* the actual decoding window */
+ ULONG window_size; /* window size (32Kb through 2Mb) */
+ ULONG actual_size; /* window size when it was first allocated */
+ ULONG window_posn; /* current offset within the window */
+ ULONG R0, R1, R2; /* for the LRU offset system */
+ UWORD main_elements; /* number of main tree elements */
+ int header_read; /* have we started decoding at all yet? */
+ UWORD block_type; /* type of this block */
+ ULONG block_length; /* uncompressed length of this block */
+ ULONG block_remaining; /* uncompressed bytes still left to decode */
+ ULONG frames_read; /* the number of CFDATA blocks processed */
+ LONG intel_filesize; /* magic header value used for transform */
+ LONG intel_curpos; /* current offset in transform space */
+ int intel_started; /* have we seen any translatable data yet? */
+
+ LZX_DECLARE_TABLE(PRETREE);
+ LZX_DECLARE_TABLE(MAINTREE);
+ LZX_DECLARE_TABLE(LENGTH);
+ LZX_DECLARE_TABLE(ALIGNED);
+};
+
+
+/* generic stuff */
+#define CAB(x) (decomp_state.x)
+#define LZX(x) (decomp_state.lzx.x)
+#define DECR_OK (0)
+#define DECR_DATAFORMAT (1)
+#define DECR_ILLEGALDATA (2)
+#define DECR_NOMEMORY (3)
+#define DECR_CHECKSUM (4)
+#define DECR_INPUT (5)
+#define DECR_OUTPUT (6)
+
+struct
+{
+ struct LZXstate lzx;
+} decomp_state;
+
+
+/* LZX decruncher */
+
+/* Microsoft's LZX document and their implementation of the
+ * com.ms.util.cab Java package do not concur.
+ *
+ * In the LZX document, there is a table showing the correlation between
+ * window size and the number of position slots. It states that the 1MB
+ * window = 40 slots and the 2MB window = 42 slots. In the implementation,
+ * 1MB = 42 slots, 2MB = 50 slots. The actual calculation is 'find the
+ * first slot whose position base is equal to or more than the required
+ * window size'. This would explain why other tables in the document refer
+ * to 50 slots rather than 42.
+ *
+ * The constant NUM_PRIMARY_LENGTHS used in the decompression pseudocode
+ * is not defined in the specification.
+ *
+ * The LZX document does not state the uncompressed block has an
+ * uncompressed length field. Where does this length field come from, so
+ * we can know how large the block is? The implementation has it as the 24
+ * bits following after the 3 blocktype bits, before the alignment
+ * padding.
+ *
+ * The LZX document states that aligned offset blocks have their aligned
+ * offset huffman tree AFTER the main and length trees. The implementation
+ * suggests that the aligned offset tree is BEFORE the main and length
+ * trees.
+ *
+ * The LZX document decoding algorithm states that, in an aligned offset
+ * block, if an extra_bits value is 1, 2 or 3, then that number of bits
+ * should be read and the result added to the match offset. This is
+ * correct for 1 and 2, but not 3, where just a huffman symbol (using the
+ * aligned tree) should be read.
+ *
+ * Regarding the E8 preprocessing, the LZX document states 'No translation
+ * may be performed on the last 6 bytes of the input block'. This is
+ * correct. However, the pseudocode provided checks for the *E8 leader*
+ * up to the last 6 bytes. If the leader appears between -10 and -7 bytes
+ * from the end, this would cause the next four bytes to be modified, at
+ * least one of which would be in the last 6 bytes, which is not allowed
+ * according to the spec.
+ *
+ * The specification states that the huffman trees must always contain at
+ * least one element. However, many CAB files contain blocks where the
+ * length tree is completely empty (because there are no matches), and
+ * this is expected to succeed.
+ */
+
+
+/* LZX uses what it calls 'position slots' to represent match offsets.
+ * What this means is that a small 'position slot' number and a small
+ * offset from that slot are encoded instead of one large offset for
+ * every match.
+ * - position_base is an index to the position slot bases
+ * - extra_bits states how many bits of offset-from-base data is needed.
+ */
+static ULONG position_base[51];
+static UBYTE extra_bits[51];
+
+
+int LZXinit(int window) {
+ ULONG wndsize = 1 << window;
+ int i, j, posn_slots;
+
+ /* LZX supports window sizes of 2^15 (32Kb) through 2^21 (2Mb) */
+ /* if a previously allocated window is big enough, keep it */
+ if (window < 15 || window > 21) return DECR_DATAFORMAT;
+ if (LZX(actual_size) < wndsize)
+ {
+ if (LZX(window)) free(LZX(window));
+ LZX(window) = NULL;
+ }
+ if (!LZX(window))
+ {
+ if (!(LZX(window) = (UBYTE*)malloc(wndsize))) return DECR_NOMEMORY;
+ LZX(actual_size) = wndsize;
+ }
+ LZX(window_size) = wndsize;
+
+ /* initialise static tables */
+ for (i=0, j=0; i <= 49; i += 2)
+ {
+ extra_bits[i] = extra_bits[i+1] = j; /* 0,0,0,0,1,1,2,2,3,3... */
+ if ((i != 0) && (j < 17)) j++; /* 0,0,1,2,3,4...15,16,17,17,17,17... */
+ }
+ for (i=0, j=0; i <= 50; i++)
+ {
+ position_base[i] = j; /* 0,1,2,3,4,6,8,12,16,24,32,... */
+ j += 1 << extra_bits[i]; /* 1,1,1,1,2,2,4,4,8,8,16,16,32,32,... */
+ }
+
+ /* calculate required position slots */
+ if (window == 20) posn_slots = 42;
+ else if (window == 21) posn_slots = 50;
+ else posn_slots = window << 1;
+
+ /*posn_slots=i=0; while (i < wndsize) i += 1 << extra_bits[posn_slots++]; */
+
+
+ LZX(R0) = LZX(R1) = LZX(R2) = 1;
+ LZX(main_elements) = LZX_NUM_CHARS + (posn_slots << 3);
+ LZX(header_read) = 0;
+ LZX(frames_read) = 0;
+ LZX(block_remaining) = 0;
+ LZX(block_type) = LZX_BLOCKTYPE_INVALID;
+ LZX(intel_curpos) = 0;
+ LZX(intel_started) = 0;
+ LZX(window_posn) = 0;
+
+ /* initialise tables to 0 (because deltas will be applied to them) */
+ for (i = 0; i < LZX_MAINTREE_MAXSYMBOLS; i++) LZX(MAINTREE_len)[i] = 0;
+ for (i = 0; i < LZX_LENGTH_MAXSYMBOLS; i++) LZX(LENGTH_len)[i] = 0;
+
+ return DECR_OK;
+}
+
+
+/* Bitstream reading macros:
+ *
+ * INIT_BITSTREAM should be used first to set up the system
+ * READ_BITS(var,n) takes N bits from the buffer and puts them in var
+ *
+ * ENSURE_BITS(n) ensures there are at least N bits in the bit buffer
+ * PEEK_BITS(n) extracts (without removing) N bits from the bit buffer
+ * REMOVE_BITS(n) removes N bits from the bit buffer
+ *
+ * These bit access routines work by using the area beyond the MSB and the
+ * LSB as a free source of zeroes. This avoids having to mask any bits.
+ * So we have to know the bit width of the bitbuffer variable. This is
+ * sizeof(ULONG) * 8, also defined as ULONG_BITS
+ */
+
+/* number of bits in ULONG. Note: This must be at multiple of 16, and at
+ * least 32 for the bitbuffer code to work (ie, it must be able to ensure
+ * up to 17 bits - that's adding 16 bits when there's one bit left, or
+ * adding 32 bits when there are no bits left. The code should work fine
+ * for machines where ULONG >= 32 bits.
+ */
+#define ULONG_BITS (sizeof(ULONG)<<3)
+
+#define INIT_BITSTREAM do { bitsleft = 0; bitbuf = 0; } while (0)
+
+#define ENSURE_BITS(n) \
+ while (bitsleft < (n)) { \
+ bitbuf |= ((inpos[1]<<8)|inpos[0]) << (ULONG_BITS-16 - bitsleft); \
+ bitsleft += 16; inpos+=2; \
+ }
+
+#define PEEK_BITS(n) (bitbuf >> (ULONG_BITS - (n)))
+#define REMOVE_BITS(n) ((bitbuf <<= (n)), (bitsleft -= (n)))
+
+#define READ_BITS(v,n) do { \
+ ENSURE_BITS(n); \
+ (v) = PEEK_BITS(n); \
+ REMOVE_BITS(n); \
+} while (0)
+
+
+/* Huffman macros */
+
+#define TABLEBITS(tbl) (LZX_##tbl##_TABLEBITS)
+#define MAXSYMBOLS(tbl) (LZX_##tbl##_MAXSYMBOLS)
+#define SYMTABLE(tbl) (LZX(tbl##_table))
+#define LENTABLE(tbl) (LZX(tbl##_len))
+
+/* BUILD_TABLE(tablename) builds a huffman lookup table from code lengths.
+ * In reality, it just calls make_decode_table() with the appropriate
+ * values - they're all fixed by some #defines anyway, so there's no point
+ * writing each call out in full by hand.
+ */
+#define BUILD_TABLE(tbl) \
+ if (make_decode_table( \
+ MAXSYMBOLS(tbl), TABLEBITS(tbl), LENTABLE(tbl), SYMTABLE(tbl) \
+ )) { return DECR_ILLEGALDATA; }
+
+
+/* READ_HUFFSYM(tablename, var) decodes one huffman symbol from the
+ * bitstream using the stated table and puts it in var.
+ */
+#define READ_HUFFSYM(tbl,var) do { \
+ ENSURE_BITS(16); \
+ hufftbl = SYMTABLE(tbl); \
+ if ((i = hufftbl[PEEK_BITS(TABLEBITS(tbl))]) >= MAXSYMBOLS(tbl)) { \
+ j = 1 << (ULONG_BITS - TABLEBITS(tbl)); \
+ do { \
+ j >>= 1; i <<= 1; i |= (bitbuf & j) ? 1 : 0; \
+ if (!j) { return DECR_ILLEGALDATA; } \
+ } while ((i = hufftbl[i]) >= MAXSYMBOLS(tbl)); \
+ } \
+ j = LENTABLE(tbl)[(var) = i]; \
+ REMOVE_BITS(j); \
+} while (0)
+
+
+/* READ_LENGTHS(tablename, first, last) reads in code lengths for symbols
+ * first to last in the given table. The code lengths are stored in their
+ * own special LZX way.
+ */
+#define READ_LENGTHS(tbl,first,last) do { \
+ lb.bb = bitbuf; lb.bl = bitsleft; lb.ip = inpos; \
+ if (lzx_read_lens(LENTABLE(tbl),(first),(last),&lb)) { \
+ return DECR_ILLEGALDATA; \
+ } \
+ bitbuf = lb.bb; bitsleft = lb.bl; inpos = lb.ip; \
+} while (0)
+
+
+/* make_decode_table(nsyms, nbits, length[], table[])
+ *
+ * This function was coded by David Tritscher. It builds a fast huffman
+ * decoding table out of just a canonical huffman code lengths table.
+ *
+ * nsyms = total number of symbols in this huffman tree.
+ * nbits = any symbols with a code length of nbits or less can be decoded
+ * in one lookup of the table.
+ * length = A table to get code lengths from [0 to syms-1]
+ * table = The table to fill up with decoded symbols and pointers.
+ *
+ * Returns 0 for OK or 1 for error
+ */
+
+int make_decode_table(ULONG nsyms, ULONG nbits, UBYTE *length, UWORD *table) {
+ register UWORD sym;
+ register ULONG leaf;
+ register UBYTE bit_num = 1;
+ ULONG fill;
+ ULONG pos = 0; /* the current position in the decode table */
+ ULONG table_mask = 1 << nbits;
+ ULONG bit_mask = table_mask >> 1; /* don't do 0 length codes */
+ ULONG next_symbol = bit_mask; /* base of allocation for long codes */
+
+ /* fill entries for codes short enough for a direct mapping */
+ while (bit_num <= nbits)
+ {
+ for (sym = 0; sym < nsyms; sym++)
+ {
+ if (length[sym] == bit_num)
+ {
+ leaf = pos;
+
+ if ((pos += bit_mask) > table_mask) return 1; /* table overrun */
+
+ /* fill all possible lookups of this symbol with the symbol itself */
+ fill = bit_mask;
+ while (fill-- > 0) table[leaf++] = sym;
+ }
+ }
+ bit_mask >>= 1;
+ bit_num++;
+ }
+
+ /* if there are any codes longer than nbits */
+ if (pos != table_mask)
+ {
+ /* clear the remainder of the table */
+ for (sym = pos; sym < table_mask; sym++) table[sym] = 0;
+
+ /* give ourselves room for codes to grow by up to 16 more bits */
+ pos <<= 16;
+ table_mask <<= 16;
+ bit_mask = 1 << 15;
+
+ while (bit_num <= 16)
+ {
+ for (sym = 0; sym < nsyms; sym++)
+ {
+ if (length[sym] == bit_num)
+ {
+ leaf = pos >> 16;
+ for (fill = 0; fill < bit_num - nbits; fill++)
+ {
+ /* if this path hasn't been taken yet, 'allocate' two entries */
+ if (table[leaf] == 0)
+ {
+ table[(next_symbol << 1)] = 0;
+ table[(next_symbol << 1) + 1] = 0;
+ table[leaf] = next_symbol++;
+ }
+ /* follow the path and select either left or right for next bit */
+ leaf = table[leaf] << 1;
+ if ((pos >> (15-fill)) & 1) leaf++;
+ }
+ table[leaf] = sym;
+
+ if ((pos += bit_mask) > table_mask) return 1; /* table overflow */
+ }
+ }
+ bit_mask >>= 1;
+ bit_num++;
+ }
+ }
+
+ /* full table? */
+ if (pos == table_mask) return 0;
+
+ /* either erroneous table, or all elements are 0 - let's find out. */
+ for (sym = 0; sym < nsyms; sym++) if (length[sym]) return 1;
+ return 0;
+}
+
+int lzx_read_lens(UBYTE *lens, ULONG first, ULONG last, lzx_bits *lb) {
+ ULONG i,j, x,y;
+ int z;
+
+ register ULONG bitbuf = lb->bb;
+ register int bitsleft = lb->bl;
+ UBYTE *inpos = lb->ip;
+ UWORD *hufftbl;
+
+ for (x = 0; x < 20; x++)
+ {
+ READ_BITS(y, 4);
+ LENTABLE(PRETREE)[x] = y;
+ }
+ BUILD_TABLE(PRETREE);
+
+ for (x = first; x < last;)
+ {
+ READ_HUFFSYM(PRETREE, z);
+ if (z == 17)
+ {
+ READ_BITS(y, 4); y += 4;
+ while (y--) lens[x++] = 0;
+ }
+ else if (z == 18)
+ {
+ READ_BITS(y, 5); y += 20;
+ while (y--) lens[x++] = 0;
+ }
+ else if (z == 19)
+ {
+ READ_BITS(y, 1); y += 4;
+ READ_HUFFSYM(PRETREE, z);
+ z = lens[x] - z; if (z < 0) z += 17;
+ while (y--) lens[x++] = z;
+ }
+ else
+ {
+ z = lens[x] - z; if (z < 0) z += 17;
+ lens[x++] = z;
+ }
+ }
+
+ lb->bb = bitbuf;
+ lb->bl = bitsleft;
+ lb->ip = inpos;
+ return 0;
+}
+
+int LZXdecompress(UBYTE* inpos, int inlen, UBYTE* outpos, int outlen) {
+ UBYTE *endinp = inpos + inlen;
+ UBYTE *window = LZX(window);
+ UBYTE *runsrc, *rundest;
+ UWORD *hufftbl; /* used in READ_HUFFSYM macro as chosen decoding table */
+
+ ULONG window_posn = LZX(window_posn);
+ ULONG window_size = LZX(window_size);
+ ULONG R0 = LZX(R0);
+ ULONG R1 = LZX(R1);
+ ULONG R2 = LZX(R2);
+
+ register ULONG bitbuf;
+ register int bitsleft;
+ ULONG match_offset, i,j,k; /* ijk used in READ_HUFFSYM macro */
+ lzx_bits lb; /* used in READ_LENGTHS macro */
+
+ int togo = outlen, this_run, main_element, aligned_bits;
+ int match_length, length_footer, extra, verbatim_bits;
+
+ INIT_BITSTREAM;
+
+ /* read header if necessary */
+ if (!LZX(header_read))
+ {
+ i = j = 0;
+ READ_BITS(k, 1); if (k)
+ {
+ READ_BITS(i,16); READ_BITS(j,16);
+ }
+ LZX(intel_filesize) = (i << 16) | j; /* or 0 if not encoded */
+ LZX(header_read) = 1;
+ }
+
+ /* main decoding loop */
+ while (togo > 0)
+ {
+ /* last block finished, new block expected */
+ if (LZX(block_remaining) == 0)
+ {
+ if (LZX(block_type) == LZX_BLOCKTYPE_UNCOMPRESSED)
+ {
+ if (LZX(block_length) & 1) inpos++; /* realign bitstream to word */
+ INIT_BITSTREAM;
+ }
+
+ READ_BITS(LZX(block_type), 3);
+ READ_BITS(i, 16);
+ READ_BITS(j, 8);
+ LZX(block_remaining) = LZX(block_length) = (i << 8) | j;
+
+ switch (LZX(block_type))
+ {
+ case LZX_BLOCKTYPE_ALIGNED:
+ for (i = 0; i < 8; i++)
+ {
+ READ_BITS(j, 3); LENTABLE(ALIGNED)[i] = j;
+ }
+ BUILD_TABLE(ALIGNED);
+ /* rest of aligned header is same as verbatim */
+
+ case LZX_BLOCKTYPE_VERBATIM:
+ READ_LENGTHS(MAINTREE, 0, 256);
+ READ_LENGTHS(MAINTREE, 256, LZX(main_elements));
+ BUILD_TABLE(MAINTREE);
+ if (LENTABLE(MAINTREE)[0xE8] != 0) LZX(intel_started) = 1;
+
+ READ_LENGTHS(LENGTH, 0, LZX_NUM_SECONDARY_LENGTHS);
+ BUILD_TABLE(LENGTH);
+ break;
+
+ case LZX_BLOCKTYPE_UNCOMPRESSED:
+ LZX(intel_started) = 1; /* because we can't assume otherwise */
+ ENSURE_BITS(16); /* get up to 16 pad bits into the buffer */
+ if (bitsleft > 16) inpos -= 2; /* and align the bitstream! */
+ R0 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4;
+ R1 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4;
+ R2 = inpos[0]|(inpos[1]<<8)|(inpos[2]<<16)|(inpos[3]<<24);inpos+=4;
+ break;
+
+ default:
+ return DECR_ILLEGALDATA;
+ }
+ }
+
+ /* buffer exhaustion check */
+ if (inpos > endinp)
+ {
+ /* it's possible to have a file where the next run is less than
+ * 16 bits in size. In this case, the READ_HUFFSYM() macro used
+ * in building the tables will exhaust the buffer, so we should
+ * allow for this, but not allow those accidentally read bits to
+ * be used (so we check that there are at least 16 bits
+ * remaining - in this boundary case they aren't really part of
+ * the compressed data)
+ */
+ if (inpos > (endinp+2) || bitsleft < 16) return DECR_ILLEGALDATA;
+ }
+
+ while ((this_run = LZX(block_remaining)) > 0 && togo > 0)
+ {
+ if (this_run > togo) this_run = togo;
+ togo -= this_run;
+ LZX(block_remaining) -= this_run;
+
+ /* apply 2^x-1 mask */
+ window_posn &= window_size - 1;
+ /* runs can't straddle the window wraparound */
+ if ((window_posn + this_run) > window_size)
+ return DECR_DATAFORMAT;
+
+ switch (LZX(block_type))
+ {
+
+ case LZX_BLOCKTYPE_VERBATIM:
+ while (this_run > 0)
+ {
+ READ_HUFFSYM(MAINTREE, main_element);
+
+ if (main_element < LZX_NUM_CHARS)
+ {
+ /* literal: 0 to LZX_NUM_CHARS-1 */
+ window[window_posn++] = main_element;
+ this_run--;
+ }
+ else
+ {
+ /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
+ main_element -= LZX_NUM_CHARS;
+
+ match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
+ if (match_length == LZX_NUM_PRIMARY_LENGTHS)
+ {
+ READ_HUFFSYM(LENGTH, length_footer);
+ match_length += length_footer;
+ }
+ match_length += LZX_MIN_MATCH;
+
+ match_offset = main_element >> 3;
+
+ if (match_offset > 2)
+ {
+ /* not repeated offset */
+ if (match_offset != 3)
+ {
+ extra = extra_bits[match_offset];
+ READ_BITS(verbatim_bits, extra);
+ match_offset = position_base[match_offset] - 2 + verbatim_bits;
+ }
+ else
+ {
+ match_offset = 1;
+ }
+
+ /* update repeated offset LRU queue */
+ R2 = R1; R1 = R0; R0 = match_offset;
+ }
+ else if (match_offset == 0)
+ {
+ match_offset = R0;
+ }
+ else if (match_offset == 1)
+ {
+ match_offset = R1;
+ R1 = R0; R0 = match_offset;
+ }
+ else /* match_offset == 2 */
+ {
+ match_offset = R2;
+ R2 = R0; R0 = match_offset;
+ }
+
+ rundest = window + window_posn;
+ runsrc = rundest - match_offset;
+ window_posn += match_length;
+ this_run -= match_length;
+
+ /* copy any wrapped around source data */
+ while ((runsrc < window) && (match_length-- > 0))
+ {
+ *rundest++ = *(runsrc + window_size); runsrc++;
+ }
+ /* copy match data - no worries about destination wraps */
+ while (match_length-- > 0) *rundest++ = *runsrc++;
+
+ }
+ }
+ break;
+
+ case LZX_BLOCKTYPE_ALIGNED:
+ while (this_run > 0)
+ {
+ READ_HUFFSYM(MAINTREE, main_element);
+
+ if (main_element < LZX_NUM_CHARS)
+ {
+ /* literal: 0 to LZX_NUM_CHARS-1 */
+ window[window_posn++] = main_element;
+ this_run--;
+ }
+ else
+ {
+ /* match: LZX_NUM_CHARS + ((slot<<3) | length_header (3 bits)) */
+ main_element -= LZX_NUM_CHARS;
+
+ match_length = main_element & LZX_NUM_PRIMARY_LENGTHS;
+ if (match_length == LZX_NUM_PRIMARY_LENGTHS)
+ {
+ READ_HUFFSYM(LENGTH, length_footer);
+ match_length += length_footer;
+ }
+ match_length += LZX_MIN_MATCH;
+
+ match_offset = main_element >> 3;
+
+ if (match_offset > 2)
+ {
+ /* not repeated offset */
+ extra = extra_bits[match_offset];
+ match_offset = position_base[match_offset] - 2;
+ if (extra > 3)
+ {
+ /* verbatim and aligned bits */
+ extra -= 3;
+ READ_BITS(verbatim_bits, extra);
+ match_offset += (verbatim_bits << 3);
+ READ_HUFFSYM(ALIGNED, aligned_bits);
+ match_offset += aligned_bits;
+ }
+ else if (extra == 3)
+ {
+ /* aligned bits only */
+ READ_HUFFSYM(ALIGNED, aligned_bits);
+ match_offset += aligned_bits;
+ }
+ else if (extra > 0)
+ { /* extra==1, extra==2 */
+ /* verbatim bits only */
+ READ_BITS(verbatim_bits, extra);
+ match_offset += verbatim_bits;
+ }
+ else /* extra == 0 */
+ {
+ /* ??? */
+ match_offset = 1;
+ }
+
+ /* update repeated offset LRU queue */
+ R2 = R1; R1 = R0; R0 = match_offset;
+ }
+ else if (match_offset == 0)
+ {
+ match_offset = R0;
+ }
+ else if (match_offset == 1)
+ {
+ match_offset = R1;
+ R1 = R0; R0 = match_offset;
+ }
+ else /* match_offset == 2 */
+ {
+ match_offset = R2;
+ R2 = R0; R0 = match_offset;
+ }
+
+ rundest = window + window_posn;
+ runsrc = rundest - match_offset;
+ window_posn += match_length;
+ this_run -= match_length;
+
+ /* copy any wrapped around source data */
+ while ((runsrc < window) && (match_length-- > 0))
+ {
+ *rundest++ = *(runsrc + window_size); runsrc++;
+ }
+ /* copy match data - no worries about destination wraps */
+ while (match_length-- > 0) *rundest++ = *runsrc++;
+
+ }
+ }
+ break;
+
+ case LZX_BLOCKTYPE_UNCOMPRESSED:
+ if ((inpos + this_run) > endinp) return DECR_ILLEGALDATA;
+ memcpy(window + window_posn, inpos, (size_t) this_run);
+ inpos += this_run; window_posn += this_run;
+ break;
+
+ default:
+ return DECR_ILLEGALDATA; /* might as well */
+ }
+
+ }
+ }
+
+ if (togo != 0) return DECR_ILLEGALDATA;
+ memcpy(outpos, window + ((!window_posn) ? window_size : window_posn) -
+ outlen, (size_t) outlen);
+
+ LZX(window_posn) = window_posn;
+ LZX(R0) = R0;
+ LZX(R1) = R1;
+ LZX(R2) = R2;
+
+ /* intel E8 decoding */
+ if ((LZX(frames_read)++ < 32768) && LZX(intel_filesize) != 0)
+ {
+ if (outlen <= 6 || !LZX(intel_started))
+ {
+ LZX(intel_curpos) += outlen;
+ }
+ else
+ {
+ UBYTE *data = outpos;
+ UBYTE *dataend = data + outlen - 10;
+ LONG curpos = LZX(intel_curpos);
+ LONG filesize = LZX(intel_filesize);
+ LONG abs_off, rel_off;
+
+ LZX(intel_curpos) = curpos + outlen;
+
+ while (data < dataend)
+ {
+ if (*data++ != 0xE8)
+ {
+ curpos++; continue;
+ }
+ abs_off = data[0] | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);
+ if ((abs_off >= -curpos) && (abs_off < filesize))
+ {
+ rel_off = (abs_off >= 0) ? abs_off - curpos : abs_off + filesize;
+ data[0] = (UBYTE) rel_off;
+ data[1] = (UBYTE) (rel_off >> 8);
+ data[2] = (UBYTE) (rel_off >> 16);
+ data[3] = (UBYTE) (rel_off >> 24);
+ }
+ data += 4;
+ curpos += 5;
+ }
+ }
+ }
+ return DECR_OK;
+}
+
diff --git a/parts/documentation/protocols/chm/decompress.h b/parts/documentation/protocols/chm/decompress.h
new file mode 100644
index 00000000..4fa42615
--- /dev/null
+++ b/parts/documentation/protocols/chm/decompress.h
@@ -0,0 +1,43 @@
+/* This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __decompress_h__
+#define __decompress_h__
+
+#ifdef __cplusplus__
+extern "C" {
+#endif
+
+typedef unsigned char UBYTE; /* 8 bits exactly */
+typedef unsigned short UWORD; /* 16 bits (or more) */
+typedef unsigned int ULONG; /* 32 bits (or more) */
+typedef signed int LONG; /* 32 bits (or more) */
+
+typedef struct lzx_bits
+{
+ ULONG bb;
+ int bl;
+ UBYTE *ip;
+} lzx_bits;
+
+int LZXinit( int window );
+int LZXdecompress( UBYTE *inpos, int inlen, UBYTE *outpos, int outlen );
+
+#ifdef __cplusplus__
+}
+#endif
+
+#endif // __decompress_h__
diff --git a/parts/documentation/protocols/chm/kchmpart.cpp b/parts/documentation/protocols/chm/kchmpart.cpp
new file mode 100644
index 00000000..b72602c3
--- /dev/null
+++ b/parts/documentation/protocols/chm/kchmpart.cpp
@@ -0,0 +1,123 @@
+/* This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#include "kchmpart.h"
+#include <qstring.h>
+
+#include <kinstance.h>
+#include <kglobal.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kstandarddirs.h>
+#include <kaboutdata.h>
+
+extern "C"
+{
+ void* init_libkchmpart()
+ {
+ return new KChmPartFactory;
+ }
+}
+
+KInstance* KChmPartFactory::s_instance = 0L;
+KAboutData* KChmPartFactory::s_about = 0L;
+
+KChmPartFactory::KChmPartFactory( QObject* parent, const char* name )
+ : KParts::Factory( parent, name )
+{
+}
+
+KChmPartFactory::~KChmPartFactory()
+{
+ delete s_instance;
+ s_instance = 0L;
+ delete s_about;
+}
+
+KParts::Part* KChmPartFactory::createPartObject( QWidget *parentWidget, const char *, QObject *,
+ const char *name, const char *, const QStringList & )
+{
+ KChmPart* part = new KChmPart( parentWidget, name );
+ return part;
+}
+
+KInstance* KChmPartFactory::instance()
+{
+ if( !s_instance )
+ {
+ s_about = new KAboutData( "kchmpart",
+ I18N_NOOP( "KChm" ), "1.0pre" );
+ s_instance = new KInstance( s_about );
+ }
+ return s_instance;
+}
+
+
+KChmPart::KChmPart( QWidget * parent, const char * name )
+ : KDevHTMLPart( ), m_job(0)
+{
+ KInstance * instance = new KInstance( "kchmpart" );
+ setInstance( instance );
+ m_extension=new KParts::BrowserExtension(this);
+ setOptions(-1);
+}
+
+bool KChmPart::openURL( const KURL &url )
+{
+ KURL chmURL = url;
+ chmURL.setProtocol("ms-its");
+ chmURL.addPath("/");
+ return KDevHTMLPart::openURL(chmURL);
+}
+
+void KChmPart::slotDuplicate()
+{
+}
+
+void KChmPart::slotOpenInNewWindow(const KURL &url)
+{
+}
+
+
+/*
+bool KChmPart::openFile()
+{
+ if (m_job!=0)
+ m_job->kill();
+
+ m_htmlData.truncate(0);
+
+ m_job = KIO::get( QString("chm:")+m_file+"/", true, false );
+ connect( m_job, SIGNAL( data( KIO::Job *, const QByteArray &) ), SLOT( readData( KIO::Job *, const QByteArray &) ) );
+ connect( m_job, SIGNAL( result( KIO::Job * ) ), SLOT( jobDone( KIO::Job * ) ) );
+ return true;
+}
+
+void KChmPart::readData(KIO::Job * , const QByteArray & data)
+{
+ m_htmlData += data;
+}
+
+void KChmPart::jobDone( KIO::Job *)
+{
+ m_job=0;
+ begin();
+ write(QString::fromLocal8Bit(m_htmlData));
+ end();
+}
+*/
+#include "kchmpart.moc"
+
diff --git a/parts/documentation/protocols/chm/kchmpart.desktop b/parts/documentation/protocols/chm/kchmpart.desktop
new file mode 100644
index 00000000..1ddefe13
--- /dev/null
+++ b/parts/documentation/protocols/chm/kchmpart.desktop
@@ -0,0 +1,46 @@
+[Desktop Entry]
+Type=Service
+Exec=foobar
+Comment=Embeddable HTMLHelp Viewer
+Comment[ca]=Visor encastat de l'ajuda HTML
+Comment[da]=Indlejrbar HTMLHjælp-fremviser
+Comment[de]=Eingebetteter Betrachter für HTMLHelp
+Comment[el]=Ενσωματωμένος προβολέας HTMLHelp
+Comment[es]=Visor de ayuda HTML empotrable
+Comment[et]=Põimitav HTML-abifailide näitaja
+Comment[eu]=HTMLHelp ikustaile kapsulagarria
+Comment[fa]=مشاهده‌گر کمک قابل نهفتۀ زنگام
+Comment[fr]=Afficheur HTMLHelp intégrable
+Comment[ga]=Comhpháirt inleabaithe amharctha HTML
+Comment[gl]=Visor de HTMLHelp incrustable
+Comment[hi]=अंतर्निर्मित योग्य एचटीएमएल मदद प्रदर्शक
+Comment[hu]=Beágyazható HTML-es dokumentációnézegető
+Comment[it]=Visualizzatore integrabile per la guida HTML
+Comment[ja]=埋め込み可能な HTMLHelp ビューア
+Comment[ms]=Pelihat HTMLHelp Terbinadalam
+Comment[nds]=Inbettbor Kieker för HTMLHelp
+Comment[ne]=सम्मिलित गर्न मिल्ने HTMLHelp दृश्यकर्ता
+Comment[nl]=Ingebedde HTML Helpweergave
+Comment[pl]=Wbudowywalna przeglądarka pomocy w formacie HTML
+Comment[pt]=Visualizador de HTMLHelp Incorporado
+Comment[pt_BR]=Visualizador de Ajuda HTML Embutido
+Comment[ru]=Встроенный просмотр HTMLHelp
+Comment[sk]=Vložiteľný HTMLHelp prezerač
+Comment[sr]=Уградиви приказивач HTMLHelp-а
+Comment[sr@Latn]=Ugradivi prikazivač HTMLHelp-a
+Comment[sv]=Inbäddningsbar HTML-hjälpvisning
+Comment[ta]=HTML உதவி பார்வையாளரை உட்பொதி
+Comment[tg]=Намоиши ҳамвори HTMLHelp
+Comment[tr]=Gömülebilir HTMLHelp Görüntüleyicisi
+Comment[zh_CN]=嵌入的 HTML 帮助查看器
+Comment[zh_TW]=可嵌入 HTMLHelp 檢視器
+MimeType=application/chm
+Name=KChmPart
+Name[de]=CHM-Betrachter (KDevelop)
+Name[hi]=के-सीएचएम-पार्ट
+Name[nds]=Chm-Kieker (KDevelop)
+Name[pl]=Program KChm
+Name[sv]=Kchm-del
+ServiceTypes=KParts/ReadOnlyPart,Browser/View
+X-KDE-Library=libkchmpart
+X-KDevelop-Version=5
diff --git a/parts/documentation/protocols/chm/kchmpart.h b/parts/documentation/protocols/chm/kchmpart.h
new file mode 100644
index 00000000..03a12738
--- /dev/null
+++ b/parts/documentation/protocols/chm/kchmpart.h
@@ -0,0 +1,82 @@
+/* This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+#ifndef __kchmpart_h__
+#define __kchmpart_h__
+
+#include <kparts/factory.h>
+#include <kparts/part.h>
+#include <kparts/browserextension.h>
+#include <khtml_part.h>
+#include <kio/job.h>
+#include <kio/jobclasses.h>
+#include <kdevhtmlpart.h>
+
+#include <qcstring.h>
+
+class KInstance;
+class KAboutData;
+
+class KChmPartFactory: public KParts::Factory
+{
+ Q_OBJECT
+ public:
+ KChmPartFactory( QObject *parent = 0, const char *name = 0 );
+ virtual ~KChmPartFactory();
+
+ virtual KParts::Part* createPartObject(
+ QWidget *parentWidget, const char *widgetName,
+ QObject *parent, const char *name,
+ const char *classname, const QStringList &args );
+
+ static KInstance *instance();
+
+ private:
+ static KInstance *s_instance;
+ static KAboutData *s_about;
+
+};
+
+
+class KChmPart : public KDevHTMLPart
+{
+ Q_OBJECT
+ public:
+ KChmPart( QWidget *, const char * = 0 );
+ KParts::BrowserExtension * extension() { return m_extension; }
+
+ public slots:
+ virtual bool openURL( const KURL & );
+/*
+ protected slots:
+ void readData(KIO::Job * , const QByteArray & data);
+ void jobDone( KIO::Job *);
+*/
+ protected:
+ //virtual bool openFile();
+ KInstance *m_instance;
+ KParts::BrowserExtension *m_extension;
+ KIO::TransferJob *m_job;
+ QCString m_htmlData;
+
+ protected slots:
+ virtual void slotDuplicate();
+ virtual void slotOpenInNewWindow(const KURL &url);
+
+};
+
+#endif // __kchmpart_h__
+