zoukankan      html  css  js  c++  java
  • 在线CHM阅读器(1)——CHM文件格式概述

    之前开源的WEBOS中有一个在线CHM阅读器,本文将介绍如何开发一个功能类似的在线CHM阅读器。

    效果图

    1

    相关技术

    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文件的方法可阅读这篇文章:

    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的目录结构。

    image

    上图是一个HHC文件的内容,大概的规律是,每一个<LI><OBJECT>…<OBJECT>对应着目录树中的一个节点,<OBJECT>…<OBJECT>中的参数记录着该节点的属性(对应的页面,名称等)。如果这个节点有子节点的话,那么<LI>后面会紧跟着一个<UL></UL>,<UL>里面所有的节点都是其子节点。

    上文已简单的介绍了如何反编译CHM的文件格式以及关键文件的格式,在下一篇文章中,将介绍如何处理目录文件(*.hhc文件)以及如何利用ISAPI筛选器在没有反编译出CHM内部文件的情况下实现一个在线CHM阅读器。

    尽管目前这个系列还没有完成,但是您可以先下载源代码预览一下这个在线CHM阅读器:

    在线CHM阅读器源代码(注意:该CHM阅读器需要用到ISAPI筛选器,请仔细阅读部署须知)

    如果您有任何问题,可以通过WebIM与我联系。


  • 相关阅读:
    教你透彻了解红黑树(转)
    算法描述伪代码
    B 树、B+ 树、B* 树
    Java四种引用类型
    Java程序以后台方式在Linux上运行(nohup命令)
    java 文档注释
    Reactor模式和NIO
    Immutable模式与string类的实现
    mina 入门
    索引和优化查询
  • 原文地址:https://www.cnblogs.com/lucc/p/1721683.html
Copyright © 2011-2022 走看看