在线CHM阅读器(1)——CHM文件格式概述
之前开源的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重定向。
3.Lesktop
Lesktop是一款用于开发RIA网站的开源JS界面库,Lesktop提供了一个功能强大的可视化开发工具帮助您快速的开发RIA网站。本文介绍的CHM在线阅读器将使用Lesktop来开发前台界面。
CHM文件格式
1.反编译CHM文件
要阅读CHM文件,首先就必须反编译CHM文件,提取出其中的文件(网页,图片等),反编译CHM文件需要用到WIN32 API的StgOpenStorage函数,.NET反编译CHM文件的方法可阅读这篇文章:
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阅读器源代码(注意:该CHM阅读器需要用到ISAPI筛选器,请仔细阅读部署须知)
如果您有任何问题,可以通过WebIM与我联系。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步