作者:卢春城
之前开源的WEBOS中有一个在线CHM阅读器,本文将介绍如何开发一个功能类似的在线CHM阅读器。
效果图

相关技术
1.Structured Storage
Structured Storage provides file and data persistence in COM by handling a single file as a structured collection of objects known as storages and streams.
The purpose of Structured Storage is to reduce the performance penalties and overhead associated with storing separate objects in a single file. Structured Storage provides a solution by defining how to handle a single file entity as a structured collection of two types of objects—storages and streams—through a standard implementation called Compound Files. This enables the user to interact with, and manage, a compound file as if it were a single file rather than a nested hierarchy of separate objects.
关于Structured Storage请查阅MSDN,CHM文件本质上就是一个结构化存储格式的文件,因此,如果要读取CHM中的文件,需要知道Structured Storage的相关API。
2.ISAPI筛选器
ISAPI(Internet Server Application Programming Interface)作为一种可用来替代CGI的方法,是由微软和Process软件公司联合提出的Web服务器上的API标准。ISAPI与Web服务器结合紧密,功能强大,能够获得大量的信息,因此利用ISAPI可以开发出灵活高效的Web服务器增强程序。实现CHM在线阅读器(在不反编译的情况下)需要使用ISAPI筛选器来实现URL重定向。
CHM文件格式
1.反编译CHM文件
要阅读CHM文件,首先就必须反编译CHM文件,提取出其中的文件(网页,图片等),反编译CHM文件需要用到WIN32 API的StgOpenStorage函数,.NET反编译CHM文件的方法可阅读这篇文章:
CHM Help File Extractor
2.#SYSTEM文件
反编译CHM文件后,您可以在解压出来的文件中看到这个名称为#SYSTEM的文件,这个文件保存了一些关于CHM文件的信息,例如起始页,标题等等。#SYSTEM是一个二进制文件,其格式也并不复杂,格式如下所示:
ID(2字节)+数据长度(2字节)+数据(字节数由数据长度决定)
#SYSTEM文件就是有多个以上这种数据构成,根据这个规律,可以读取出所有ID对应的数据,并保存到一个Hashtable中,代码如下:
private bool ReadSession(BinaryReader reader)
{
if (reader.BaseStream.Position >= reader.BaseStream.Length) return false;
UInt16 id = reader.ReadUInt16();
UInt16 count = reader.ReadUInt16();
if (count + reader.BaseStream.Position <= reader.BaseStream.Length)
{
if (count > 0)
{
_session[id] = reader.ReadBytes(count);
}
return true;
}
else
{
return false;
}
}
public ChmInfo(Stream stream)
{
BinaryReader reader = new BinaryReader(stream);
while (ReadSession(reader)) ;
}
目前可以确定的ID和数据对应关系如下:
0x0002 - 起始页的路径
0x0003 - 标题
0x0004 - 语言
根据这个对应关系,就可以读取出CHM文件的标题,起始页等。
3.目录文件(*.hhc)
如果CHM带有目录的话,反编译CHM文件后,您可以在解压出来的文件中看到一个扩展名为HHC的文件,这个文件保存了CHM的目录结构。

上图是一个HHC文件的内容,大概的规律是,每一个<LI><OBJECT>…<OBJECT>对应着目录树中的一个节点,<OBJECT>…<OBJECT>中的参数记录着该节点的属性(对应的页面,名称等)。如果这个节点有子节点的话,那么<LI>后面会紧跟着一个<UL></UL>,<UL>里面所有的节点都是其子节点。
上文已简单的介绍了如何反编译CHM的文件格式以及关键文件的格式,在下一篇文章中,将介绍如何处理目录文件(*.hhc文件)以及如何利用ISAPI筛选器在没有反编译出CHM内部文件的情况下实现一个在线CHM阅读器。
尽管目前这个系列还没有完成,但是您可以先下载源代码预览一下这个在线CHM阅读器:
CHM在线阅读器源代码下载
|
更新于:2013-08-30 12:51:49