KDevelop API Documentation

parts/doctreeview/chm/chmfile.cpp

Go to the documentation of this file.
00001 /* This library is free software; you can redistribute it and/or 00002 modify it under the terms of the GNU Library General Public 00003 License as published by the Free Software Foundation; either 00004 version 2 of the License, or (at your option) any later version. 00005 00006 This library is distributed in the hope that it will be useful, 00007 but WITHOUT ANY WARRANTY; without even the implied warranty of 00008 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00009 Library General Public License for more details. 00010 00011 You should have received a copy of the GNU Library General Public License 00012 along with this library; see the file COPYING.LIB. If not, write to 00013 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00014 Boston, MA 02111-1307, USA. 00015 */ 00016 00017 #include <qfile.h> 00018 #include "chmfile.h" 00019 #include "decompress.h" 00020 00021 uint Chm::getEncInt(QFile& f, uint &value) const 00022 { 00023 int c; 00024 uint result = 0; 00025 ulong count = 0; 00026 00027 do 00028 { 00029 c = f.getch(); 00030 result <<= 7; 00031 result |= (c & 0x7F); 00032 count++; 00033 } while (c & 0x80); 00034 00035 value = result; 00036 return count; 00037 } 00038 00039 uint Chm::getName(QFile& f, QString& name) const 00040 { 00041 int len = f.getch(); 00042 char *buf = new char[len]; 00043 f.readBlock(buf, len); 00044 name = QString::fromUtf8(buf, len); 00045 if (name.startsWith("/")) 00046 name = name.lower(); 00047 delete buf; 00048 return len + 1; 00049 } 00050 00051 uint Chm::getIntel32(QFile& f) const 00052 { 00053 uint value = f.getch() | f.getch() << 8 | f.getch() << 16 | f.getch() << 24; 00054 return value; 00055 } 00056 00057 uint Chm::getIntel64(QFile& f) const 00058 { 00059 uint value = getIntel32(f); 00060 f.at(f.at() + 4); 00061 return value; 00062 } 00063 00064 bool Chm::getChunk(QFile& f, uint chunkSize, ChmDirectoryMap& directoryMap) const 00065 { 00066 char tag[4]; 00067 if (f.readBlock(tag, 4) != 4) return false; 00068 00069 if (!qstrncmp(tag, "PMGL", 4)) 00070 { 00071 uint quickref_length = getIntel32(f); 00072 f.at(f.at() + 12); 00073 00074 uint pos = 20; 00075 while (pos < chunkSize - quickref_length) 00076 { 00077 uint section, offset, length; 00078 QString name; 00079 pos += getName(f, name); 00080 pos += getEncInt(f, section); 00081 pos += getEncInt(f, offset); 00082 pos += getEncInt(f, length); 00083 directoryMap[name] = ChmDirTableEntry(section, offset, length); 00084 if (name.endsWith(".hhc")) 00085 directoryMap["/@contents"] = ChmDirTableEntry(section, offset, length); 00086 } 00087 00088 return (f.at(f.at() + quickref_length)); 00089 } 00090 else if (!qstrncmp(tag, "PMGI", 4)) 00091 { 00092 // evaluation of the index chunk is not yet implemented => skip it 00093 return f.at(f.at() + chunkSize - 4); 00094 } 00095 else 00096 { 00097 return false; 00098 } 00099 } 00100 00101 bool Chm::read(const QString& fileSpec, ChmDirectoryMap& dirMap, QByteArray& contents) const 00102 { 00103 QFile f(fileSpec); 00104 if (!f.open(IO_ReadOnly)) return false; 00105 00106 // read CHM file header 00107 char tag[4]; 00108 if (f.readBlock(tag, 4) != 4 || qstrncmp(tag, "ITSF", 4)) return false; 00109 uint chm_version = getIntel32(f); 00110 if (!f.at(f.at() + 0x30)) return false; 00111 00112 // read header section table 00113 uint section_0_offset = getIntel64(f); 00114 uint section_0_length = getIntel64(f); 00115 uint section_1_offset = getIntel64(f); 00116 uint section_1_length = getIntel64(f); 00117 00118 uint contentStart = 0; 00119 if (chm_version >= 3) contentStart = getIntel32(f); 00120 00121 // read directory header 00122 if (!f.at(section_1_offset)) return false; 00123 if (f.readBlock(tag, 4) != 4 || qstrncmp(tag, "ITSP", 4)) return false; 00124 if (!f.at(f.at() + 12)) return false; 00125 uint directory_chunk_size = getIntel32(f); 00126 if (!f.at(f.at() + 24)) return false; 00127 uint num_directory_chunks = getIntel32(f); 00128 if (!f.at(f.at() + 36)) return false; 00129 00130 // read directory table 00131 for (uint i = 0; i < num_directory_chunks; i++) 00132 if (!getChunk(f, directory_chunk_size, dirMap)) return false; 00133 00134 // current position is start of content area 00135 if (chm_version < 3) contentStart = f.at(); 00136 00137 // read reset table 00138 if (!f.at(contentStart)) return false; 00139 uint resetTableOffset = 00140 dirMap["::DataSpace/Storage/MSCompressed/Transform/{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/InstanceData/ResetTable"].offset; 00141 if (!f.at(f.at() + resetTableOffset + 4)) return false; 00142 uint numResetTableEntries = getIntel32(f); 00143 if (!f.at(f.at() + 8)) return false; 00144 uint uncompressedLength = getIntel64(f); 00145 uint compressedLength = getIntel64(f); 00146 uint blockSize = getIntel64(f); 00147 uint *resetTable = new uint[numResetTableEntries + 1]; 00148 00149 for (uint i = 0; i < numResetTableEntries; i++) 00150 resetTable[i] = getIntel64(f); 00151 00152 resetTable[numResetTableEntries] = compressedLength; 00153 00154 // read compressed contents 00155 if (!f.at(contentStart)) return false; 00156 uint contentsOffset = dirMap["::DataSpace/Storage/MSCompressed/Content"].offset; 00157 if (!f.at(f.at() + contentsOffset)) return false; 00158 char *compressedContents = new char[compressedLength]; 00159 if ((uint)f.readBlock(compressedContents, compressedLength) != compressedLength) return false; 00160 00161 f.close(); 00162 00163 // allocate buffer for uncompressed contents 00164 char *uncompressedContents = new char[uncompressedLength]; 00165 00166 // get window size 00167 uint window = 1; 00168 uint tmp = blockSize; 00169 while (tmp >>= 1) window++; 00170 00171 // decompress 00172 uint outlen = uncompressedLength; 00173 int res = 1; 00174 00175 for (uint i = 0; i < numResetTableEntries; i++) 00176 { 00177 if (!(i & 1)) LZXinit(window); 00178 00179 uint inlen = resetTable[i+1] - resetTable[i]; 00180 res = LZXdecompress((uchar*)&compressedContents[resetTable[i]], 00181 inlen, 00182 (uchar*)uncompressedContents + i * blockSize, 00183 (outlen < blockSize) ? outlen : blockSize); 00184 if (res) break; 00185 outlen -= blockSize; 00186 } 00187 00188 delete [] resetTable; 00189 delete [] compressedContents; 00190 00191 if (res == 0) 00192 contents.duplicate(uncompressedContents, uncompressedLength); 00193 00194 delete [] uncompressedContents; 00195 00196 return (res == 0); 00197 }
KDE Logo
This file is part of the documentation for KDevelop Version 3.0.4.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Oct 19 08:01:50 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003