找回密码
 注册
查看: 713|回复: 2

我在这里下载的chmlib安装后样本文件不能编译,大家来看看

[复制链接]
发表于 2003-8-5 09:23:32 | 显示全部楼层 |阅读模式
这里是install文件开头部件。

CHMLIB 0.3 Installation
=======================

Linux
-----
1. Edit the Makefile (yeah, yeah, I know...  it's archaic and I should be
   using automake or something...).  There are not many settings you need to
   modify here.  Basically, there are three defines you may want to modify:

   CHM_MT:              build library with synchronization for thread-safety
   CHM_USE_PREAD:       use pread instead of lseek/read
   CHM_USE_IO64:        support 64-bit file I/O

   Modify the INSTALLPREFIX to change the installation location.

2. make

3. su
   make install

To use the library, see chm_lib.h, and the included example programs:

    test_chmLib.c
    enum_chmLib.c
    chm_http.c

库文件我已经安装上了,在/usr/local/lib下,/etc/ld.so.conf也已经编缉过了,路径已经加进去了。并且ldconfig。

但编译时gcc test_chmLib.c说unreference sybol什么的我也记不清了。就是找不到函数。下面是几个文件的内容,有空大家看一下吧。
/* $Id: chm_lib.h,v 1.10 2002/10/09 01:16:33 jedwin Exp $ */
/***************************************************************************
*             chm_lib.h - CHM archive manipulation routines               *
*                           -------------------                           *
*                                                                         *
*  author:     Jed Wing <[email protected]>                         *
*  version:    0.3                                                        *
*  notes:      These routines are meant for the manipulation of microsoft *
*              .chm (compiled html help) files, but may likely be used    *
*              for the manipulation of any ITSS archive, if ever ITSS     *
*              archives are used for any other purpose.                   *
*                                                                         *
*              Note also that the section names are statically handled.   *
*              To be entirely correct, the section names should be read   *
*              from the section names meta-file, and then the various     *
*              content sections and the "transforms" to apply to the data *
*              they contain should be inferred from the section name and  *
*              the meta-files referenced using that name; however, all of *
*              the files I've been able to get my hands on appear to have *
*              only two sections: Uncompressed and MSCompressed.          *
*              Additionally, the ITSS.DLL file included with Windows does *
*              not appear to handle any different transforms than the     *
*              simple LZX-transform.  Furthermore, the list of transforms *
*              to apply is broken, in that only half the required space   *
*              is allocated for the list.  (It appears as though the      *
*              space is allocated for ASCII strings, but the strings are  *
*              written as unicode.  As a result, only the first half of   *
*              the string appears.)  So this is probably not too big of   *
*              a deal, at least until CHM v4 (MS .lit files), which also  *
*              incorporate encryption, of some description.               *
***************************************************************************/

/***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU Lesser General Public License as        *
*   published by the Free Software Foundation; either version 2.1 of the  *
*   License, or (at your option) any later version.                       *
*                                                                         *
***************************************************************************/

#ifndef INCLUDED_CHMLIB_H
#define INCLUDED_CHMLIB_H

#ifdef __cplusplus
extern "C" {
#endif

#ifdef WIN32
typedef unsigned __int64 LONGUINT64;
typedef __int64          LONGINT64;
#else
typedef unsigned long long LONGUINT64;
typedef long long          LONGINT64;
#endif

/* the two available spaces in a CHM file                      */
/* N.B.: The format supports arbitrarily many spaces, but only */
/*       two appear to be used at present.                     */
#define CHM_UNCOMPRESSED (0)
#define CHM_COMPRESSED   (1)

/* structure representing an ITS (CHM) file stream             */
struct chmFile;

/* structure representing an element from an ITS file stream   */
#define CHM_MAX_PATHLEN  (256)
struct chmUnitInfo
{
    LONGUINT64         start;
    LONGUINT64         length;
    int                space;
    char               path[CHM_MAX_PATHLEN+1];
};

/* open an ITS archive */
struct chmFile* chm_open(const char *filename);

/* close an ITS archive */
void chm_close(struct chmFile *h);

/* methods for ssetting tuning parameters for particular file */
#define CHM_PARAM_MAX_BLOCKS_CACHED 0
void chm_set_param(struct chmFile *h,
                   int paramType,
                   int paramVal);

/* resolve a particular object from the archive */
#define CHM_RESOLVE_SUCCESS (0)
#define CHM_RESOLVE_FAILURE (1)
int chm_resolve_object(struct chmFile *h,
                       const char *objPath,
                       struct chmUnitInfo *ui);

/* retrieve part of an object from the archive */
LONGINT64 chm_retrieve_object(struct chmFile *h,
                              struct chmUnitInfo *ui,
                              unsigned char *buf,
                              LONGUINT64 addr,
                              LONGINT64 len);

/* enumerate the objects in the .chm archive */
typedef int (*CHM_ENUMERATOR)(struct chmFile *h,
                              struct chmUnitInfo *ui,
                              void *context);
#define CHM_ENUMERATE_NORMAL    (1)
#define CHM_ENUMERATE_META      (2)
#define CHM_ENUMERATE_SPECIAL   (4)
#define CHM_ENUMERATE_FILES     (
#define CHM_ENUMERATE_DIRS      (16)
#define CHM_ENUMERATE_ALL       (31)
#define CHM_ENUMERATOR_FAILURE  (0)
#define CHM_ENUMERATOR_CONTINUE (1)
#define CHM_ENUMERATOR_SUCCESS  (2)
int chm_enumerate(struct chmFile *h,
                  int what,
                  CHM_ENUMERATOR e,
                  void *context);

int chm_enumerate_dir(struct chmFile *h,
                      const char *prefix,
                      int what,
                      CHM_ENUMERATOR e,
                      void *context);

#ifdef __cplusplus
}
#endif

#endif /* INCLUDED_CHMLIB_H */


/* $Id: chm_lib.c,v 1.18 2002/10/10 03:24:51 jedwin Exp $ */
/***************************************************************************
*             chm_lib.c - CHM archive manipulation routines               *
*                           -------------------                           *
*                                                                         *
*  author:     Jed Wing <[email protected]>                         *
*  version:    0.3                                                        *
*  notes:      These routines are meant for the manipulation of microsoft *
*              .chm (compiled html help) files, but may likely be used    *
*              for the manipulation of any ITSS archive, if ever ITSS     *
*              archives are used for any other purpose.                   *
*                                                                         *
*              Note also that the section names are statically handled.   *
*              To be entirely correct, the section names should be read   *
*              from the section names meta-file, and then the various     *
*              content sections and the "transforms" to apply to the data *
*              they contain should be inferred from the section name and  *
*              the meta-files referenced using that name; however, all of *
*              the files I've been able to get my hands on appear to have *
*              only two sections: Uncompressed and MSCompressed.          *
*              Additionally, the ITSS.DLL file included with Windows does *
*              not appear to handle any different transforms than the     *
*              simple LZX-transform.  Furthermore, the list of transforms *
*              to apply is broken, in that only half the required space   *
*              is allocated for the list.  (It appears as though the      *
*              space is allocated for ASCII strings, but the strings are  *
*              written as unicode.  As a result, only the first half of   *
*              the string appears.)  So this is probably not too big of   *
*              a deal, at least until CHM v4 (MS .lit files), which also  *
*              incorporate encryption, of some description.               *
*                                                                         *
* switches:    CHM_MT:        compile library with thread-safety          *
*                                                                         *
* switches (Linux only):                                                  *
*              CHM_USE_PREAD: compile library to use pread instead of     *
*                             lseek/read                                  *
*              CHM_USE_IO64:  compile library to support full 64-bit I/O  *
*                             as is needed to properly deal with the      *
*                             64-bit file offsets.                        *
***************************************************************************/

/***************************************************************************
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU Lesser General Public License as        *
*   published by the Free Software Foundation; either version 2.1 of the  *
*   License, or (at your option) any later version.                       *
*                                                                         *
***************************************************************************/

#include "chm_lib.h"

#ifdef CHM_MT
#define _REENTRANT
#endif

#include "lzx.h"

#include <stdlib.h>
#include <string.h>

#if __sun || __sgi
#include <strings.h>
#endif

#ifdef WIN32
#include <windows.h>
#include <malloc.h>
#else
/* basic Linux system includes */
#define _XOPEN_SOURCE 500
#include <unistd.h>
#include &lt;sys/types.h&gt;
#include &lt;sys/stat.h&gt;
#include &lt;fcntl.h&gt;
/* #include &lt;dmalloc.h&gt; */
#endif

/* includes/defines for threading, if using them */
#ifdef CHM_MT
#ifdef WIN32
#define CHM_ACQUIRE_LOCK(a) do {                        \
        EnterCriticalSection(&amp;(a));                     \
    } while(0)
#define CHM_RELEASE_LOCK(a) do {                        \
        EnterCriticalSection(&amp;(a));                     \
    } while(0)

#else
#include &lt;pthread.h&gt;

#define CHM_ACQUIRE_LOCK(a) do {                        \
        pthread_mutex_lock(&amp;(a));                       \
    } while(0)
#define CHM_RELEASE_LOCK(a) do {                        \
        pthread_mutex_unlock(&amp;(a));                     \
    } while(0)

#endif
#else
#define CHM_ACQUIRE_LOCK(a) /* do nothing */
#define CHM_RELEASE_LOCK(a) /* do nothing */
#endif

#ifdef WIN32
#define CHM_NULL_FD (INVALID_HANDLE_VALUE)
#define CHM_USE_WIN32IO 1
#define CHM_CLOSE_FILE(fd) CloseHandle((fd))
#else
#define CHM_NULL_FD (-1)
#define CHM_CLOSE_FILE(fd) close((fd))
#endif

/*
* defines related to tuning
*/
#ifndef CHM_MAX_BLOCKS_CACHED
#define CHM_MAX_BLOCKS_CACHED 5
#endif

/*
* architecture specific defines
*
* Note: as soon as C99 is more widespread, the below defines should
* probably just use the C99 sized-int types.
*
* The following settings will probably work for many platforms.  The sizes
* don't have to be exactly correct, but the types must accommodate at least as
* many bits as they specify.
*/

/* i386, 32-bit, Windows */
#ifdef WIN32
typedef unsigned char           UChar;
typedef __int16                 Int16;
typedef unsigned __int16        UInt16;
typedef __int32                 Int32;
typedef unsigned __int32        UInt32;
typedef __int64                 Int64;
typedef unsigned __int64        UInt64;

/* I386, 32-bit, non-Windows */
/* Sparc        */
/* MIPS         */
#elif __i386__ || __sun || __sgi
typedef unsigned char           UChar;
typedef short                   Int16;
typedef unsigned short          UInt16;
typedef long                    Int32;
typedef unsigned long           UInt32;
typedef long long               Int64;
typedef unsigned long long      UInt64;
#else

/* yielding an error is preferable to yielding incorrect behavior */
#error "Please define the sized types for your platform in chm_lib.c"
#endif

/* GCC */
#ifdef __GNUC__
#define memcmp __builtin_memcmp
#define memcpy __builtin_memcpy
#define strlen __builtin_strlen

#elif defined(WIN32)
static int ffs(unsigned int val)
{
        int bit=1, idx=1;
        while (bit != 0  &amp;&amp;  (val &amp; bit) == 0)
        {
                bit &lt;&lt;= 1;
                ++idx;
        }
        if (bit == 0)
                return 0;
        else
                return idx;
}

#endif

/* utilities for unmarshalling data */
static int _unmarshal_char_array(unsigned char **pData,
                                 unsigned long *pLenRemain,
                                 char *dest,
                                 int count)
{
    if (count &lt;= 0  ||  (unsigned int)count &gt; *pLenRemain)
        return 0;
    memcpy(dest, (*pData), count);
    *pData += count;
    *pLenRemain -= count;
    return 1;
}

static int _unmarshal_uchar_array(unsigned char **pData,
                                  unsigned long *pLenRemain,
                                  unsigned char *dest,
                                  int count)
{
        if (count &lt;= 0  ||  (unsigned int)count &gt; *pLenRemain)
        return 0;
    memcpy(dest, (*pData), count);
    *pData += count;
    *pLenRemain -= count;
    return 1;
}

static int _unmarshal_int16(unsigned char **pData,
                            unsigned long *pLenRemain,
                            Int16 *dest)
{
    if (2 &gt; *pLenRemain)
        return 0;
    *dest = (*pData)[0] | (*pData)[1]&lt;&lt;8;
    *pData += 2;
    *pLenRemain -= 2;
    return 1;
}

static int _unmarshal_uint16(unsigned char **pData,
                             unsigned long *pLenRemain,
                             UInt16 *dest)
{
    if (2 &gt; *pLenRemain)
        return 0;
    *dest = (*pData)[0] | (*pData)[1]&lt;&lt;8;
    *pData += 2;
    *pLenRemain -= 2;
    return 1;
}

static int _unmarshal_int32(unsigned char **pData,
                            unsigned long *pLenRemain,
                            Int32 *dest)
{
    if (4 &gt; *pLenRemain)
        return 0;
    *dest = (*pData)[0] | (*pData)[1]&lt;&lt;8 | (*pData)[2]&lt;&lt;16 | (*pData)[3]&lt;&lt;24;
    *pData += 4;
    *pLenRemain -= 4;
    return 1;
}

static int _unmarshal_uint32(unsigned char **pData,
                             unsigned long *pLenRemain,
                             UInt32 *dest)
{
    if (4 &gt; *pLenRemain)
        return 0;
    *dest = (*pData)[0] | (*pData)[1]&lt;&lt;8 | (*pData)[2]&lt;&lt;16 | (*pData)[3]&lt;&lt;24;
    *pData += 4;
    *pLenRemain -= 4;
    return 1;
}

static int _unmarshal_int64(unsigned char **pData,
                            unsigned long *pLenRemain,
                            Int64 *dest)
{
    Int64 temp;
    int i;
    if (8 &gt; *pLenRemain)
        return 0;
    temp=0;
    for(i=8; i&gt;0; i--)
    {
        temp &lt;&lt;= 8;
        temp |= (*pData)[i-1];
    }
    *dest = temp;
    *pData += 8;
    *pLenRemain -= 8;
    return 1;
}

static int _unmarshal_uint64(unsigned char **pData,
                             unsigned long *pLenRemain,
                             UInt64 *dest)
{
    UInt64 temp;
    int i;
    if (8 &gt; *pLenRemain)
        return 0;
    temp=0;
    for(i=8; i&gt;0; i--)
    {
        temp &lt;&lt;= 8;
        temp |= (*pData)[i-1];
    }
    *dest = temp;
    *pData += 8;
    *pLenRemain -= 8;
    return 1;
}

static int _unmarshal_uuid(unsigned char **pData,
                           unsigned long *pDataLen,
                           unsigned char *dest)
{
    return _unmarshal_uchar_array(pData, pDataLen, dest, 16);
}

/* names of sections essential to decompression */
static const char _CHMU_RESET_TABLE[] =
        "::DataSpace/Storage/MSCompressed/Transform/"
        "{7FC28940-9D31-11D0-9B27-00A0C91E9C7C}/"
        "InstanceData/ResetTable";
static const char _CHMU_LZXC_CONTROLDATA[] =
        "::DataSpace/Storage/MSCompressed/ControlData";
static const char _CHMU_CONTENT[] =
        "::DataSpace/Storage/MSCompressed/Content";
static const char _CHMU_SPANINFO[] =
        "::DataSpace/Storage/MSCompressed/SpanInfo";

/*
* structures local to this module
*/

/* structure of ITSF headers */
#define _CHM_ITSF_V2_LEN (0x5
#define _CHM_ITSF_V3_LEN (0x60)
struct chmItsfHeader
{
    char        signature[4];           /*  0 (ITSF) */
    Int32       version;                /*  4 */
    Int32       header_len;             /*  8 */
    Int32       unknown_000c;           /*  c */
    UInt32      last_modified;          /* 10 */
    UInt32      lang_id;                /* 14 */
    UChar       dir_uuid[16];           /* 18 */
    UChar       stream_uuid[16];        /* 28 */
    UInt64      unknown_offset;         /* 38 */
    UInt64      unknown_len;            /* 40 */
    UInt64      dir_offset;             /* 48 */
    UInt64      dir_len;                /* 50 */
    UInt64      data_offset;            /* 58 (Not present before V3) */
}; /* __attribute__ ((aligned (1))); */

static int _unmarshal_itsf_header(unsigned char **pData,
                                  unsigned long *pDataLen,
                                  struct chmItsfHeader *dest)
{
    /* we only know how to deal with the 0x58 and 0x60 byte structures */
    if (*pDataLen != _CHM_ITSF_V2_LEN  &amp;&amp;  *pDataLen != _CHM_ITSF_V3_LEN)
        return 0;

    /* unmarshal common fields */
    _unmarshal_char_array(pData, pDataLen,  dest-&gt;signature, 4);
    _unmarshal_int32     (pData, pDataLen, &amp;dest-&gt;version);
    _unmarshal_int32     (pData, pDataLen, &amp;dest-&gt;header_len);
    _unmarshal_int32     (pData, pDataLen, &amp;dest-&gt;unknown_000c);
    _unmarshal_uint32    (pData, pDataLen, &amp;dest-&gt;last_modified);
    _unmarshal_uint32    (pData, pDataLen, &amp;dest-&gt;lang_id);
    _unmarshal_uuid      (pData, pDataLen,  dest-&gt;dir_uuid);
    _unmarshal_uuid      (pData, pDataLen,  dest-&gt;stream_uuid);
    _unmarshal_uint64    (pData, pDataLen, &amp;dest-&gt;unknown_offset);
    _unmarshal_uint64    (pData, pDataLen, &amp;dest-&gt;unknown_len);
    _unmarshal_uint64    (pData, pDataLen, &amp;dest-&gt;dir_offset);
    _unmarshal_uint64    (pData, pDataLen, &amp;dest-&gt;dir_len);

    /* error check the data */
    /* XXX: should also check UUIDs, probably, though with a version 3 file,
     * current MS tools do not seem to use them.
     */
    if (memcmp(dest-&gt;signature, "ITSF", 4) != 0)
        return 0;
    if (dest-&gt;version == 2)
    {
        if (dest-&gt;header_len &lt; _CHM_ITSF_V2_LEN)
            return 0;
    }
    else if (dest-&gt;version == 3)
    {
        if (dest-&gt;header_len &lt; _CHM_ITSF_V3_LEN)
            return 0;
    }
    else
        return 0;

    /* now, if we have a V3 structure, unmarshal the rest.
     * otherwise, compute it
     */
    if (dest-&gt;version == 3)
    {
        if (*pDataLen != 0)
            _unmarshal_uint64(pData, pDataLen, &amp;dest-&gt;data_offset);
        else
            return 0;
    }
    else
        dest-&gt;data_offset = dest-&gt;dir_offset + dest-&gt;dir_len;

    return 1;
}

/* structure of ITSP headers */
#define _CHM_ITSP_V1_LEN (0x54)
struct chmItspHeader
{
    char        signature[4];           /*  0 (ITSP) */
    Int32       version;                /*  4 */
    Int32       header_len;             /*  8 */
    Int32       unknown_000c;           /*  c */
    UInt32      block_len;              /* 10 */
    Int32       blockidx_intvl;         /* 14 */
    Int32       index_depth;            /* 18 */
    Int32       index_root;             /* 1c */
    Int32       index_head;             /* 20 */
    Int32       unknown_0024;           /* 24 */
    UInt32      num_blocks;             /* 28 */
    Int32       unknown_002c;           /* 2c */
    UInt32      lang_id;                /* 30 */
    UChar       system_uuid[16];        /* 34 */
    UChar       unknown_0044[16];       /* 44 */
}; /* __attribute__ ((aligned (1))); */

static int _unmarshal_itsp_header(unsigned char **pData,
                                  unsigned long *pDataLen,
                                  struct chmItspHeader *dest)
{
    /* we only know how to deal with a 0x54 byte structures */
    if (*pDataLen != _CHM_ITSP_V1_LEN)
        return 0;

    /* unmarshal fields */
    _unmarshal_char_array(pData, pDataLen,  dest-&gt;signature, 4);
    _unmarshal_int32     (pData, pDataLen, &amp;dest-&gt;version);
    _unmarshal_int32     (pData, pDataLen, &amp;dest-&gt;header_len);
    _unmarshal_int32     (pData, pDataLen, &amp;dest-&gt;unknown_000c);
    _unmarshal_uint32    (pData, pDataLen, &amp;dest-&gt;block_len);
    _unmarshal_int32     (pData, pDataLen, &amp;dest-&gt;blockidx_intvl);
    _unmarshal_int32     (pData, pDataLen, &amp;dest-&gt;index_depth);
    _unmarshal_int32     (pData, pDataLen, &amp;dest-&gt;index_root);
    _unmarshal_int32     (pData, pDataLen, &amp;dest-&gt;index_head);
    _unmarshal_int32     (pData, pDataLen, &amp;dest-&gt;unknown_0024);
    _unmarshal_uint32    (pData, pDataLen, &amp;dest-&gt;num_blocks);
    _unmarshal_int32     (pData, pDataLen, &amp;dest-&gt;unknown_002c);
    _unmarshal_uint32    (pData, pDataLen, &amp;dest-&gt;lang_id);
    _unmarshal_uuid      (pData, pDataLen,  dest-&gt;system_uuid);
    _unmarshal_uchar_array(pData, pDataLen, dest-&gt;unknown_0044, 16);

    /* error check the data */
    if (memcmp(dest-&gt;signature, "ITSP", 4) != 0)
        return 0;
    if (dest-&gt;version != 1)
        return 0;
    if (dest-&gt;header_len != _CHM_ITSP_V1_LEN)
        return 0;

    return 1;
}

/* structure of PMGL headers */
static const char _chm_pmgl_marker[4] = "PMGL";
#define _CHM_PMGL_LEN (0x14)
struct chmPmglHeader
{
    char        signature[4];           /*  0 (PMGL) */
    UInt32      free_space;             /*  4 */
    UInt32      unknown_0008;           /*  8 */
    Int32       block_prev;             /*  c */
    Int32       block_next;             /* 10 */
}; /* __attribute__ ((aligned (1))); */

static int _unmarshal_pmgl_header(unsigned char **pData,
                                  unsigned long *pDataLen,
                                  struct chmPmglHeader *dest)
{
    /* we only know how to deal with a 0x14 byte structures */
    if (*pDataLen != _CHM_PMGL_LEN)
        return 0;

    /* unmarshal fields */
    _unmarshal_char_array(pData, pDataLen,  dest-&gt;signature, 4);
    _unmarshal_uint32    (pData, pDataLen, &amp;dest-&gt;free_space);
    _unmarshal_uint32    (pData, pDataLen, &amp;dest-&gt;unknown_000;
    _unmarshal_int32     (pData, pDataLen, &amp;dest-&gt;block_prev);
    _unmarshal_int32     (pData, pDataLen, &amp;dest-&gt;block_next);

    /* check structure */
    if (memcmp(dest-&gt;signature, _chm_pmgl_marker, 4) != 0)
        return 0;

    return 1;
}

/* structure of PMGI headers */
static const char _chm_pmgi_marker[4] = "PMGI";
#define _CHM_PMGI_LEN (0x0
struct chmPmgiHeader
{
    char        signature[4];           /*  0 (PMGI) */
    UInt32      free_space;             /*  4 */
}; /* __attribute__ ((aligned (1))); */

static int _unmarshal_pmgi_header(unsigned char **pData,
                                  unsigned long *pDataLen,
                                  struct chmPmgiHeader *dest)
{
    /* we only know how to deal with a 0x8 byte structures */
    if (*pDataLen != _CHM_PMGI_LEN)
        return 0;

    /* unmarshal fields */
    _unmarshal_char_array(pData, pDataLen,  dest-&gt;signature, 4);
    _unmarshal_uint32    (pData, pDataLen, &amp;dest-&gt;free_space);

    /* check structure */
    if (memcmp(dest-&gt;signature, _chm_pmgi_marker, 4) != 0)
        return 0;

    return 1;
}

/* structure of LZXC reset table */
#define _CHM_LZXC_RESETTABLE_V1_LEN (0x2
struct chmLzxcResetTable
{
    UInt32      version;
    UInt32      block_count;
    UInt32      unknown;
    UInt32      table_offset;
    UInt64      uncompressed_len;
    UInt64      compressed_len;
    UInt64      block_len;     
}; /* __attribute__ ((aligned (1))); */

static int _unmarshal_lzxc_reset_table(unsigned char **pData,
                                       unsigned long *pDataLen,
                                       struct chmLzxcResetTable *dest)
{
    /* we only know how to deal with a 0x28 byte structures */
    if (*pDataLen != _CHM_LZXC_RESETTABLE_V1_LEN)
        return 0;

    /* unmarshal fields */
    _unmarshal_uint32    (pData, pDataLen, &amp;dest-&gt;version);
    _unmarshal_uint32    (pData, pDataLen, &amp;dest-&gt;block_count);
    _unmarshal_uint32    (pData, pDataLen, &amp;dest-&gt;unknown);
    _unmarshal_uint32    (pData, pDataLen, &amp;dest-&gt;table_offset);
    _unmarshal_uint64    (pData, pDataLen, &amp;dest-&gt;uncompressed_len);
    _unmarshal_uint64    (pData, pDataLen, &amp;dest-&gt;compressed_len);
    _unmarshal_uint64    (pData, pDataLen, &amp;dest-&gt;block_len);

    /* check structure */
    if (dest-&gt;version != 2)
        return 0;

    return 1;
}

/* structure of LZXC control data block */
#define _CHM_LZXC_MIN_LEN (0x1
#define _CHM_LZXC_V2_LEN (0x1c)
struct chmLzxcControlData
{
    UInt32      size;                   /*  0        */
    char        signature[4];           /*  4 (LZXC) */
    UInt32      version;                /*  8        */
    UInt32      resetInterval;          /*  c        */
    UInt32      windowSize;             /* 10        */
    UInt32      unknown_14;             /* 14        */
    UInt32      unknown_18;             /* 18        */
};

static int _unmarshal_lzxc_control_data(unsigned char **pData,
                                        unsigned long *pDataLen,
                                        struct chmLzxcControlData *dest)
{
    /* we want at least 0x18 bytes */
    if (*pDataLen &lt; _CHM_LZXC_MIN_LEN)
        return 0;

    /* unmarshal fields */
    _unmarshal_uint32    (pData, pDataLen, &amp;dest-&gt;size);
    _unmarshal_char_array(pData, pDataLen,  dest-&gt;signature, 4);
    _unmarshal_uint32    (pData, pDataLen, &amp;dest-&gt;version);
    _unmarshal_uint32    (pData, pDataLen, &amp;dest-&gt;resetInterval);
    _unmarshal_uint32    (pData, pDataLen, &amp;dest-&gt;windowSize);
    _unmarshal_uint32    (pData, pDataLen, &amp;dest-&gt;unknown_14);

    if (*pDataLen &gt;= _CHM_LZXC_V2_LEN)
        _unmarshal_uint32    (pData, pDataLen, &amp;dest-&gt;unknown_1;
    else
        dest-&gt;unknown_18 = 0;

    if (dest-&gt;version == 2)
    {
        dest-&gt;resetInterval *= 0x8000;
        dest-&gt;windowSize *= 0x8000;
        dest-&gt;unknown_14 *= 0x8000;
    }
    if (dest-&gt;windowSize == 0  ||  dest-&gt;resetInterval == 0)
        return 0;

    /* for now, only support resetInterval a multiple of windowSize/2 */
    if (dest-&gt;windowSize == 1)
        return 0;
    if ((dest-&gt;resetInterval % (dest-&gt;windowSize/2)) != 0)
        return 0;

    /* check structure */
    if (memcmp(dest-&gt;signature, "LZXC", 4) != 0)
        return 0;

    return 1;
}

/* the structure used for chm file handles */
struct chmFile
{
#ifdef WIN32
    HANDLE              fd;
#else
    int                 fd;
#endif

#ifdef CHM_MT
#ifdef WIN32
    CRITICAL_SECTION    mutex;
    CRITICAL_SECTION    lzx_mutex;
    CRITICAL_SECTION    cache_mutex;
#else
    pthread_mutex_t     mutex;
    pthread_mutex_t     lzx_mutex;
    pthread_mutex_t     cache_mutex;
#endif
#endif

    UInt64              dir_offset;
    UInt64              dir_len;   
    UInt64              data_offset;
    Int32               index_root;
    Int32               index_head;
    UInt32              block_len;     

    UInt64              span;
    struct chmUnitInfo  rt_unit;
    struct chmUnitInfo  cn_unit;
    struct chmLzxcResetTable reset_table;

    /* LZX control data */
    UInt32              window_size;
    UInt32              reset_interval;
    UInt32              reset_blkcount;

    /* decompressor state */
    struct LZXstate    *lzx_state;
    int                 lzx_last_block;

    /* cache for decompressed blocks */
    UChar             **cache_blocks;
    Int64              *cache_block_indices;
    Int32               cache_num_blocks;
};

/*
* utility functions local to this module
*/

/* utility function to handle differences between {pread,read}(64)? */
static Int64 _chm_fetch_bytes(struct chmFile *h,
                              UChar *buf,
                              UInt64 os,
                              Int64 len)
{
    Int64 readLen=0, oldOs=0;
    if (h-&gt;fd  ==  CHM_NULL_FD)
        return readLen;

    CHM_ACQUIRE_LOCK(h-&gt;mutex);
#ifdef CHM_USE_WIN32IO
    /* NOTE: this might be better done with CreateFileMapping, et cetera... */
    {
        DWORD origOffsetLo=0, origOffsetHi=0;
        DWORD offsetLo, offsetHi;
        DWORD actualLen=0;

        /* awkward Win32 Seek/Tell */
        offsetLo = (unsigned long)(os &amp; 0xffffffffL);
        offsetHi = (unsigned long)((os &gt;&gt; 32) &amp; 0xffffffffL);
        origOffsetLo = SetFilePointer(h-&gt;fd, 0, &amp;origOffsetHi, FILE_CURRENT);
        offsetLo = SetFilePointer(h-&gt;fd, offsetLo, &amp;offsetHi, FILE_BEGIN);

        /* read the data */
        if (ReadFile(h-&gt;fd,
                     buf,
                     (DWORD)len,
                     &amp;actualLen,
                     NULL) == TRUE)
            readLen = actualLen;
        else
            readLen = 0;

        /* restore original position */
        SetFilePointer(h-&gt;fd, origOffsetLo, &amp;origOffsetHi, FILE_BEGIN);
    }
#else
#ifdef CHM_USE_PREAD
#ifdef CHM_USE_IO64
    readLen = pread64(h-&gt;fd, buf, (long)len, os);
#else
    readLen = pread(h-&gt;fd, buf, (long)len, (unsigned long)os);
#endif
#else
#ifdef CHM_USE_IO64
    oldOs = lseek64(h-&gt;fd, 0, SEEK_CUR);
    lseek64(h-&gt;fd, os, SEEK_SET);
    readLen = read(h-&gt;fd, buf, len);
    lseek64(h-&gt;fd, oldOs, SEEK_SET);
#else
    oldOs = lseek(h-&gt;fd, 0, SEEK_CUR);
    lseek(h-&gt;fd, (long)os, SEEK_SET);
    readLen = read(h-&gt;fd, buf, len);
    lseek(h-&gt;fd, (long)oldOs, SEEK_SET);
#endif
#endif
#endif
    CHM_RELEASE_LOCK(h-&gt;mutex);
    return readLen;
}

/* open an ITS archive */
struct chmFile *chm_open(const char *filename)
{
    unsigned char               sbuffer[256];
    unsigned long               sremain;
    unsigned char              *sbufpos;
    struct chmFile             *newHandle=NULL;
    struct chmItsfHeader        itsfHeader;
    struct chmItspHeader        itspHeader;
    struct chmUnitInfo          uiSpan;
    struct chmUnitInfo          uiLzxc;
    struct chmLzxcControlData   ctlData;

    /* allocate handle */
    newHandle = (struct chmFile *)malloc(sizeof(struct chmFile));
    newHandle-&gt;fd = CHM_NULL_FD;
    newHandle-&gt;lzx_state = NULL;
    newHandle-&gt;cache_blocks = NULL;
    newHandle-&gt;cache_block_indices = NULL;
    newHandle-&gt;cache_num_blocks = 0;

    /* open file */
#ifdef WIN32
    if ((newHandle-&gt;fd=CreateFileA(filename,
                                   GENERIC_READ,
                                   0,
                                   NULL,
                                   OPEN_EXISTING,
                                   FILE_ATTRIBUTE_NORMAL,
                                   NULL)) == CHM_NULL_FD)
    {
        free(newHandle);
        return NULL;
    }
#else
    if ((newHandle-&gt;fd=open(filename, O_RDONLY)) == CHM_NULL_FD)
    {
        free(newHandle);
        return NULL;
    }
#endif

    /* initialize mutexes, if needed */
#ifdef CHM_MT
#ifdef WIN32
    InitializeCriticalSection(&amp;newHandle-&gt;mutex);
    InitializeCriticalSection(&amp;newHandle-&gt;lzx_mutex);
    InitializeCriticalSection(&amp;newHandle-&gt;cache_mutex);
#else
    pthread_mutex_init(&amp;newHandle-&gt;mutex, NULL);
    pthread_mutex_init(&amp;newHandle-&gt;lzx_mutex, NULL);
    pthread_mutex_init(&amp;newHandle-&gt;cache_mutex, NULL);
#endif
#endif

    /* read and verify header */
    sremain = _CHM_ITSF_V3_LEN;
    sbufpos = sbuffer;
    if (_chm_fetch_bytes(newHandle, sbuffer, (UInt64)0, sremain) != sremain    ||
        !_unmarshal_itsf_header(&amp;sbufpos, &amp;sremain, &amp;itsfHeader))
    {
        chm_close(newHandle);
        return NULL;
    }

    /* stash important values from header */
    newHandle-&gt;dir_offset  = itsfHeader.dir_offset;
    newHandle-&gt;dir_len     = itsfHeader.dir_len;
    newHandle-&gt;data_offset = itsfHeader.data_offset;

    /* now, read and verify the directory header chunk */
    sremain = _CHM_ITSP_V1_LEN;
    sbufpos = sbuffer;
    if (_chm_fetch_bytes(newHandle, sbuffer,
                         (UInt64)itsfHeader.dir_offset, sremain) != sremain       ||
        !_unmarshal_itsp_header(&amp;sbufpos, &amp;sremain, &amp;itspHeader))
    {
        chm_close(newHandle);
        return NULL;
    }

    /* grab essential information from ITSP header */
    newHandle-&gt;dir_offset += itspHeader.header_len;
    newHandle-&gt;dir_len    -= itspHeader.header_len;
    newHandle-&gt;index_root  = itspHeader.index_root;
    newHandle-&gt;index_head  = itspHeader.index_head;
    newHandle-&gt;block_len   = itspHeader.block_len;

    /* if the index root is -1, this means we don't have any PMGI blocks.
     * as a result, we must use the sole PMGL block as the index root
     */
    if (newHandle-&gt;index_root == -1)
        newHandle-&gt;index_root = newHandle-&gt;index_head;

    /* prefetch most commonly needed unit infos */
    if (CHM_RESOLVE_SUCCESS != chm_resolve_object(newHandle,
                                                  _CHMU_SPANINFO,
                                                  &amp;uiSpan)                ||
        uiSpan.space == CHM_COMPRESSED                                    ||
        CHM_RESOLVE_SUCCESS != chm_resolve_object(newHandle,
                                                  _CHMU_RESET_TABLE,
                                                  &amp;newHandle-&gt;rt_unit)    ||
        newHandle-&gt;rt_unit.space == CHM_COMPRESSED                        ||
        CHM_RESOLVE_SUCCESS != chm_resolve_object(newHandle,
                                                  _CHMU_CONTENT,
                                                  &amp;newHandle-&gt;cn_unit)    ||
        newHandle-&gt;cn_unit.space == CHM_COMPRESSED                        ||
        CHM_RESOLVE_SUCCESS != chm_resolve_object(newHandle,
                                                  _CHMU_LZXC_CONTROLDATA,
                                                  &amp;uiLzxc)                ||
        uiLzxc.space == CHM_COMPRESSED)
    {
        chm_close(newHandle);
        return NULL;
    }

    /* try to read span */
    /* N.B.: we've already checked that uiSpan is in the uncompressed section,
     *       so this should not require attempting to decompress, which may
     *       rely on having a valid "span"
     */
    sremain = 8;
    sbufpos = sbuffer;
    if (chm_retrieve_object(newHandle, &amp;uiSpan, sbuffer,
                            0, sremain) != sremain                        ||
        !_unmarshal_uint64(&amp;sbufpos, &amp;sremain, &amp;newHandle-&gt;span))
    {
        chm_close(newHandle);
        return NULL;
    }

    /* read reset table info */
    sremain = _CHM_LZXC_RESETTABLE_V1_LEN;
    sbufpos = sbuffer;
    if (chm_retrieve_object(newHandle, &amp;newHandle-&gt;rt_unit, sbuffer,
                            0, sremain) != sremain                        ||
        !_unmarshal_lzxc_reset_table(&amp;sbufpos, &amp;sremain,
                                     &amp;newHandle-&gt;reset_table))
    {
        chm_close(newHandle);
        return NULL;
    }

    /* read control data */
    sremain = (unsigned long)uiLzxc.length;
    sbufpos = sbuffer;
    if (chm_retrieve_object(newHandle, &amp;uiLzxc, sbuffer,
                             0, sremain) != sremain                       ||
        !_unmarshal_lzxc_control_data(&amp;sbufpos, &amp;sremain,
                                      &amp;ctlData))
    {
        chm_close(newHandle);
        return NULL;
    }
    newHandle-&gt;window_size = ctlData.windowSize;
    newHandle-&gt;reset_interval = ctlData.resetInterval;
    newHandle-&gt;reset_blkcount = newHandle-&gt;reset_interval /
                               (newHandle-&gt;window_size / 2);

    /* initialize cache */
    chm_set_param(newHandle, CHM_PARAM_MAX_BLOCKS_CACHED,
                  CHM_MAX_BLOCKS_CACHED);

    return newHandle;
}

/* close an ITS archive */
void chm_close(struct chmFile *h)
{
    if (h != NULL)
    {
        if (h-&gt;fd != CHM_NULL_FD)
            CHM_CLOSE_FILE(h-&gt;fd);
        h-&gt;fd = CHM_NULL_FD;

#ifdef CHM_MT
#ifdef WIN32
        DeleteCriticalSection(&amp;h-&gt;mutex);
        DeleteCriticalSection(&amp;h-&gt;lzx_mutex);
        DeleteCriticalSection(&amp;h-&gt;cache_mutex);
#else
        pthread_mutex_destroy(&amp;h-&gt;mutex);
        pthread_mutex_destroy(&amp;h-&gt;lzx_mutex);
        pthread_mutex_destroy(&amp;h-&gt;cache_mutex);
#endif
#endif

        if (h-&gt;lzx_state)
            LZXteardown(h-&gt;lzx_state);
        h-&gt;lzx_state = NULL;

        if (h-&gt;cache_blocks)
        {
            int i;
            for (i=0; i&lt;h-&gt;cache_num_blocks; i++)
            {
                if (h-&gt;cache_blocks)
                    free(h-&gt;cache_blocks);
            }
            free(h-&gt;cache_blocks);
            h-&gt;cache_blocks = NULL;
        }

        if (h-&gt;cache_block_indices)
            free(h-&gt;cache_block_indices);
        h-&gt;cache_block_indices = NULL;

        free(h);
    }
}

/*
* set a parameter on the file handle.
* valid parameter types:
*          CHM_PARAM_MAX_BLOCKS_CACHED:
*                 how many decompressed blocks should be cached?  A simple
*                 caching scheme is used, wherein the index of the block is
*                 used as a hash value, and hash collision results in the
*                 invalidation of the previously cached block.
*/
void chm_set_param(struct chmFile *h,
                   int paramType,
                   int paramVal)
{
    switch (paramType)
    {
        case CHM_PARAM_MAX_BLOCKS_CACHED:
            CHM_ACQUIRE_LOCK(h-&gt;cache_mutex);
            if (paramVal != h-&gt;cache_num_blocks)
            {
                UChar **newBlocks;
                UInt64 *newIndices;
                int     i;

                /* allocate new cached blocks */
                newBlocks = (UChar **)malloc(paramVal * sizeof (UChar *));
                newIndices = (UInt64 *)malloc(paramVal * sizeof (UInt64));
                for (i=0; i&lt;paramVal; i++)
                {
                    newBlocks = NULL;
                    newIndices = 0;
                }

                /* re-distribute old cached blocks */
                if (h-&gt;cache_blocks)
                {
                    for (i=0; i&lt;h-&gt;cache_num_blocks; i++)
                    {
                        int newSlot = (int)(h-&gt;cache_block_indices % paramVal);

                        if (h-&gt;cache_blocks)
                        {
                            /* in case of collision, destroy newcomer */
                            if (newBlocks[newSlot])
                            {
                                free(h-&gt;cache_blocks);
                                h-&gt;cache_blocks = NULL;
                            }
                            else
                            {
                                newBlocks[newSlot] = h-&gt;cache_blocks;
                                newIndices[newSlot] =
                                            h-&gt;cache_block_indices;
                            }
                        }
                    }

                    free(h-&gt;cache_blocks);
                    free(h-&gt;cache_block_indices);
                }

                /* now, set new values */
                h-&gt;cache_blocks = newBlocks;
                h-&gt;cache_block_indices = newIndices;
                h-&gt;cache_num_blocks = paramVal;
            }
            CHM_RELEASE_LOCK(h-&gt;cache_mutex);
            break;

        default:
            break;
    }
}

/*
* helper methods for chm_resolve_object
*/

/* skip a compressed dword */
static void _chm_skip_cword(UChar **pEntry)
{
    while (*(*pEntry)++ &gt;= 0x80)
        ;
}

/* skip the data from a PMGL entry */
static void _chm_skip_PMGL_entry_data(UChar **pEntry)
{
    _chm_skip_cword(pEntry);
    _chm_skip_cword(pEntry);
    _chm_skip_cword(pEntry);
}

/* parse a compressed dword */
static UInt64 _chm_parse_cword(UChar **pEntry)
{
    UInt64 accum = 0;
    UChar temp;
    while ((temp=*(*pEntry)++) &gt;= 0x80)
    {
        accum &lt;&lt;= 7;
        accum += temp &amp; 0x7f;
    }

    return (accum &lt;&lt; 7) + temp;
}

/* parse a utf-8 string into an ASCII char buffer */
static int _chm_parse_UTF8(UChar **pEntry, UInt64 count, char *path)
{
    /* XXX: implement UTF-8 support, including a real mapping onto
     *      ISO-8859-1?  probably there is a library to do this?  As is
     *      immediately apparent from the below code, I'm only handling files
     *      in which none of the strings contain UTF-8 multi-byte characters.
     */
    while (count != 0)
    {
        if (*(*pEntry) &gt; 0x7f)
            return 0;

        *path++ = (char)(*(*pEntry)++);
        --count;
    }

    *path = '\0';
    return 1;
}

/* parse a PMGL entry into a chmUnitInfo struct; return 1 on success. */
static int _chm_parse_PMGL_entry(UChar **pEntry, struct chmUnitInfo *ui)
{
    UInt64 strLen;

    /* parse str len */
    strLen = _chm_parse_cword(pEntry);
    if (strLen &gt; CHM_MAX_PATHLEN)
        return 0;

    /* parse path */
    if (! _chm_parse_UTF8(pEntry, strLen, ui-&gt;path))
        return 0;

    /* parse info */
    ui-&gt;space  = (int)_chm_parse_cword(pEntry);
    ui-&gt;start  = _chm_parse_cword(pEntry);
    ui-&gt;length = _chm_parse_cword(pEntry);
    return 1;
}

/* find an exact entry in PMGL; return NULL if we fail */
static UChar *_chm_find_in_PMGL(UChar *page_buf,
                         UInt32 block_len,
                         const char *objPath)
{
    /* XXX: modify this to do a binary search using the nice index structure
     *      that is provided for us.
     */
    struct chmPmglHeader header;
    UInt32 hremain;
    UChar *end;
    UChar *cur;
    UChar *temp;
    UInt64 strLen;
    char buffer[CHM_MAX_PATHLEN+1];

    /* figure out where to start and end */
    cur = page_buf;
    hremain = _CHM_PMGL_LEN;
    if (! _unmarshal_pmgl_header(&amp;cur, &amp;hremain, &amp;header))
        return NULL;
    end = page_buf + block_len - (header.free_space);

    /* now, scan progressively */
    while (cur &lt; end)
    {
        /* grab the name */
        temp = cur;
        strLen = _chm_parse_cword(&amp;cur);
        if (! _chm_parse_UTF8(&amp;cur, strLen, buffer))
            return NULL;

        /* check if it is the right name */
#ifdef WIN32
                if (! stricmp(buffer, objPath))
                        return temp;
#else
        if (! strcasecmp(buffer, objPath))
            return temp;
#endif

        _chm_skip_PMGL_entry_data(&amp;cur);
    }

    return NULL;
}

/* find which block should be searched next for the entry; -1 if no block */
static Int32 _chm_find_in_PMGI(UChar *page_buf,
                        UInt32 block_len,
                        const char *objPath)
{
    /* XXX: modify this to do a binary search using the nice index structure
     *      that is provided for us
     */
    struct chmPmgiHeader header;
    UInt32 hremain;
    int page=-1;
    UChar *end;
    UChar *cur;
    UInt64 strLen;
    char buffer[CHM_MAX_PATHLEN+1];

    /* figure out where to start and end */
    cur = page_buf;
    hremain = _CHM_PMGI_LEN;
    if (! _unmarshal_pmgi_header(&amp;cur, &amp;hremain, &amp;header))
        return -1;
    end = page_buf + block_len - (header.free_space);

    /* now, scan progressively */
    while (cur &lt; end)
    {
        /* grab the name */
        strLen = _chm_parse_cword(&amp;cur);
        if (! _chm_parse_UTF8(&amp;cur, strLen, buffer))
            return -1;

        /* check if it is the right name */
#ifdef WIN32
        if (stricmp(buffer, objPath) &gt; 0)
            return page;
#else
        if (strcasecmp(buffer, objPath) &gt; 0)
            return page;
#endif

        /* load next value for path */
        page = (int)_chm_parse_cword(&amp;cur);
    }

    return page;
}

/* resolve a particular object from the archive */
int chm_resolve_object(struct chmFile *h,
                       const char *objPath,
                       struct chmUnitInfo *ui)
{
    /*
     * XXX: implement caching scheme for dir pages
     */

    Int32 curPage;

    /* buffer to hold whatever page we're looking at */
#ifdef WIN32
        UChar *page_buf = alloca(h-&gt;block_len);
#else
    UChar page_buf[h-&gt;block_len];
#endif

    /* starting page */
    curPage = h-&gt;index_root;

    /* until we have either returned or given up */
    while (curPage != -1)
    {

        /* try to fetch the index page */
        if (_chm_fetch_bytes(h, page_buf,
                             (UInt64)h-&gt;dir_offset + (UInt64)curPage*h-&gt;block_len,
                             h-&gt;block_len) != h-&gt;block_len)
            return CHM_RESOLVE_FAILURE;

        /* now, if it is a leaf node: */
        if (memcmp(page_buf, _chm_pmgl_marker, 4) == 0)
        {
            /* scan block */
            UChar *pEntry = _chm_find_in_PMGL(page_buf,
                                              h-&gt;block_len,
                                              objPath);
            if (pEntry == NULL)
                return CHM_RESOLVE_FAILURE;

            /* parse entry and return */
            _chm_parse_PMGL_entry(&amp;pEntry, ui);
            return CHM_RESOLVE_SUCCESS;
        }

        /* else, if it is a branch node: */
        else if (memcmp(page_buf, _chm_pmgi_marker, 4) == 0)
            curPage = _chm_find_in_PMGI(page_buf, h-&gt;block_len, objPath);

        /* else, we are confused.  give up. */
        else
            return CHM_RESOLVE_FAILURE;
    }

        /* didn't find anything.  fail. */
        return CHM_RESOLVE_FAILURE;
}

/*
* utility methods for dealing with compressed data
*/

/* get the bounds of a compressed block.  return 0 on failure */
static int _chm_get_cmpblock_bounds(struct chmFile *h,
                             UInt64 block,
                             UInt64 *start,
                             Int64 *len)
{
    UChar buffer[8], *dummy;
    UInt32 remain;

    /* for all but the last block, use the reset table */
    if (block &lt; h-&gt;reset_table.block_count-1)
    {
        /* unpack the start address */
        dummy = buffer;
        remain = 8;
        if (_chm_fetch_bytes(h, buffer,
                             (UInt64)h-&gt;data_offset
                                + (UInt64)h-&gt;rt_unit.start
                                + (UInt64)h-&gt;reset_table.table_offset
                                + (UInt64)block*8,
                             remain) != remain                            ||
            !_unmarshal_uint64(&amp;dummy, &amp;remain, start))
            return 0;

        /* unpack the end address */
        dummy = buffer;
        remain = 8;
        if (_chm_fetch_bytes(h, buffer,
                         (UInt64)h-&gt;data_offset
                                + (UInt64)h-&gt;rt_unit.start
                                + (UInt64)h-&gt;reset_table.table_offset
                                + (UInt64)block*8 + 8,
                         remain) != remain                                ||
            !_unmarshal_int64(&amp;dummy, &amp;remain, len))
            return 0;
    }

    /* for the last block, use the span in addition to the reset table */
    else
    {
        /* unpack the start address */
        dummy = buffer;
        remain = 8;
        if (_chm_fetch_bytes(h, buffer,
                             (UInt64)h-&gt;data_offset
                                + (UInt64)h-&gt;rt_unit.start
                                + (UInt64)h-&gt;reset_table.table_offset
                                + (UInt64)block*8,
                             remain) != remain                            ||
            !_unmarshal_uint64(&amp;dummy, &amp;remain, start))
            return 0;

        *len = h-&gt;reset_table.compressed_len;
    }

    /* compute the length and absolute start address */
    *len -= *start;
    *start += h-&gt;data_offset + h-&gt;cn_unit.start;

    return 1;
}

/* decompress the block.  must have lzx_mutex. */
static Int64 _chm_decompress_block(struct chmFile *h,
                                   UInt64 block,
                                   UChar **ubuffer)
{
#ifdef WIN32
        UChar *cbuffer = alloca(((unsigned int)h-&gt;reset_table.block_len + 6144));
#else
    UChar cbuffer[h-&gt;reset_table.block_len + 6144];     /* compressed buffer */
#endif
    UInt64 cmpStart;                                    /* compressed start  */
    Int64 cmpLen;                                       /* compressed len    */
    int indexSlot;                                      /* cache index slot  */
    UChar *lbuffer;                                     /* local buffer ptr  */
    UInt32 blockAlign = (UInt32)(block % h-&gt;reset_blkcount); /* reset intvl. aln. */
    UInt32 i;                                           /* local loop index  */

    /* check if we need previous blocks */
    if (blockAlign != 0)
    {
        /* fetch all required previous blocks since last reset */
        for (i = h-&gt;reset_blkcount - blockAlign; i &gt; 0; i--)
        {

            /* check if we most recently decompressed the previous block */
            if (h-&gt;lzx_last_block != block-i)
            {
                indexSlot = (int)((block-i) % h-&gt;cache_num_blocks);
                h-&gt;cache_block_indices[indexSlot] = block-i;
                if (! h-&gt;cache_blocks[indexSlot])
                    h-&gt;cache_blocks[indexSlot] = (UChar *)malloc(
                                            (unsigned int)(h-&gt;reset_table.block_len));
                lbuffer = h-&gt;cache_blocks[indexSlot];

                /* decompress the previous block */
                LZXreset(h-&gt;lzx_state);
                if (!_chm_get_cmpblock_bounds(h, block-i, &amp;cmpStart, &amp;cmpLen) ||
                    _chm_fetch_bytes(h, cbuffer, cmpStart, cmpLen) != cmpLen  ||
                    LZXdecompress(h-&gt;lzx_state, cbuffer, lbuffer, (int)cmpLen,
                                  (int)h-&gt;reset_table.block_len) != DECR_OK)
                    return (Int64)0;
            }

            h-&gt;lzx_last_block = (int)(block - i);
        }
    }
    else
        LZXreset(h-&gt;lzx_state);

    /* allocate slot in cache */
    indexSlot = (int)(block % h-&gt;cache_num_blocks);
    h-&gt;cache_block_indices[indexSlot] = block;
    if (! h-&gt;cache_blocks[indexSlot])
        h-&gt;cache_blocks[indexSlot] = (UChar *)malloc(
                                          ((unsigned int)h-&gt;reset_table.block_len));
    lbuffer = h-&gt;cache_blocks[indexSlot];
    *ubuffer = lbuffer;

    /* decompress the block we actually want */
    if (! _chm_get_cmpblock_bounds(h, block, &amp;cmpStart, &amp;cmpLen)          ||
        _chm_fetch_bytes(h, cbuffer, cmpStart, cmpLen) != cmpLen          ||
        LZXdecompress(h-&gt;lzx_state, cbuffer, lbuffer, (int)cmpLen,
                      (int)h-&gt;reset_table.block_len) != DECR_OK)
        return (Int64)0;
    h-&gt;lzx_last_block = (int)block;

    /* XXX: modify LZX routines to return the length of the data they
     * decompressed and return that instead, for an extra sanity check.
     */
    return h-&gt;reset_table.block_len;
}

/* grab a region from a compressed block */
static Int64 _chm_decompress_region(struct chmFile *h,
                                    UChar *buf,
                                    UInt64 start,
                                    Int64 len)
{
    UInt64 nBlock, nOffset;
    UInt64 nLen;
    UInt64 gotLen;
    UChar *ubuffer;

        if (len &lt;= 0)
                return (Int64)0;

    /* figure out what we need to read */
    nBlock = start / h-&gt;reset_table.block_len;
    nOffset = start % h-&gt;reset_table.block_len;
    nLen = len;
    if (nLen &gt; (h-&gt;reset_table.block_len - nOffset))
        nLen = h-&gt;reset_table.block_len - nOffset;

    /* if block is cached, return data from it. */
    CHM_ACQUIRE_LOCK(h-&gt;lzx_mutex);
    CHM_ACQUIRE_LOCK(h-&gt;cache_mutex);
    if (h-&gt;cache_block_indices[nBlock % h-&gt;cache_num_blocks] == nBlock    &amp;&amp;
        h-&gt;cache_blocks[nBlock % h-&gt;cache_num_blocks] != NULL)
    {
        memcpy(buf,
               h-&gt;cache_blocks[nBlock % h-&gt;cache_num_blocks] + nOffset,
               (unsigned int)nLen);
        CHM_RELEASE_LOCK(h-&gt;cache_mutex);
        CHM_RELEASE_LOCK(h-&gt;lzx_mutex);
        return nLen;
    }
    CHM_RELEASE_LOCK(h-&gt;cache_mutex);

    /* data request not satisfied, so... start up the decompressor machine */
    if (! h-&gt;lzx_state)
    {
        int window_size = ffs(h-&gt;window_size) - 1;
        h-&gt;lzx_last_block = -1;
        h-&gt;lzx_state = LZXinit(window_size);
    }

    /* decompress some data */
    gotLen = _chm_decompress_block(h, nBlock, &amp;ubuffer);
    if (gotLen &lt; nLen)
        nLen = gotLen;
    memcpy(buf, ubuffer+nOffset, (unsigned int)nLen);
    CHM_RELEASE_LOCK(h-&gt;lzx_mutex);
    return nLen;
}

/* retrieve (part of) an object */
LONGINT64 chm_retrieve_object(struct chmFile *h,
                               struct chmUnitInfo *ui,
                               unsigned char *buf,
                               LONGUINT64 addr,
                               LONGINT64 len)
{
    /* must be valid file handle */
    if (h == NULL)
        return (Int64)0;

    /* starting address must be in correct range */
    if (addr &lt; 0  ||  addr &gt;= ui-&gt;length)
        return (Int64)0;

    /* clip length */
    if (addr + len &gt; ui-&gt;length)
        len = ui-&gt;length - addr;

    /* if the file is uncompressed, it's simple */
    if (ui-&gt;space == CHM_UNCOMPRESSED)
    {
        /* read data */
        return _chm_fetch_bytes(h,
                                buf,
                                (UInt64)h-&gt;data_offset + (UInt64)ui-&gt;start + (UInt64)addr,
                                len);
    }

    /* else if the file is compressed, it's a little trickier */
    else /* ui-&gt;space == CHM_COMPRESSED */
    {
        Int64 swath=0, total=0;
        do {

            /* swill another mouthful */
            swath = _chm_decompress_region(h, buf, ui-&gt;start + addr, len);

            /* if we didn't get any... */
            if (swath == 0)
                return total;

            /* update stats */
            total += swath;
            len -= swath;
            addr += swath;
            buf += swath;

        } while (len != 0);

        return total;
    }
}

/* enumerate the objects in the .chm archive */
int chm_enumerate(struct chmFile *h,
                  int what,
                  CHM_ENUMERATOR e,
                  void *context)
{
    Int32 curPage;

    /* buffer to hold whatever page we're looking at */
#ifdef WIN32
        UChar *page_buf = alloca((unsigned int)h-&gt;block_len);
#else
    UChar page_buf[h-&gt;block_len];
#endif
    struct chmPmglHeader header;
    UChar *end;
    UChar *cur;
    unsigned long lenRemain;

    /* the current ui */
    struct chmUnitInfo ui;
    int flag;

    /* starting page */
    curPage = h-&gt;index_head;

    /* until we have either returned or given up */
    while (curPage != -1)
    {

        /* try to fetch the index page */
        if (_chm_fetch_bytes(h,
                             page_buf,
                             (UInt64)h-&gt;dir_offset + (UInt64)curPage*h-&gt;block_len,
                             h-&gt;block_len) != h-&gt;block_len)
            return 0;

        /* figure out start and end for this page */
        cur = page_buf;
        lenRemain = _CHM_PMGL_LEN;
        if (! _unmarshal_pmgl_header(&amp;cur, &amp;lenRemain, &amp;header))
            return 0;
        end = page_buf + h-&gt;block_len - (header.free_space);

        /* loop over this page */
        while (cur &lt; end)
        {
            if (! _chm_parse_PMGL_entry(&amp;cur, &amp;ui))
                return 0;

            /* check for DIRS */
            if (ui.length == 0  &amp;&amp;  !(what &amp; CHM_ENUMERATE_DIRS))
                continue;

            /* check for FILES */
            if (ui.length != 0  &amp;&amp;  !(what &amp; CHM_ENUMERATE_FILES))
                continue;

            /* check for NORMAL vs. META */
            if (ui.path[0] == '/')
            {

                /* check for NORMAL vs. SPECIAL */
                if (ui.path[1] == '#'  ||  ui.path[1] == '$')
                    flag = CHM_ENUMERATE_SPECIAL;
                else
                    flag = CHM_ENUMERATE_NORMAL;
            }
            else
                flag = CHM_ENUMERATE_META;
            if (! (what &amp; flag))
                continue;

            /* call the enumerator */
            {
                int status = (*e)(h, &amp;ui, context);
                switch (status)
                {
                    case CHM_ENUMERATOR_FAILURE:  return 0;
                    case CHM_ENUMERATOR_CONTINUE: break;
                    case CHM_ENUMERATOR_SUCCESS:  return 1;
                    default:                      break;
                }
            }
        }

        /* advance to next page */
        curPage = header.block_next;
    }

    return 1;
}

int chm_enumerate_dir(struct chmFile *h,
                      const char *prefix,
                      int what,
                      CHM_ENUMERATOR e,
                      void *context)
{
    /*
     * XXX: do this efficiently (i.e. using the tree index)
     */

    Int32 curPage;

    /* buffer to hold whatever page we're looking at */
#ifdef WIN32
        UChar *page_buf = alloca((unsigned int)h-&gt;block_len);
#else
    UChar page_buf[h-&gt;block_len];
#endif
    struct chmPmglHeader header;
    UChar *end;
    UChar *cur;
    unsigned long lenRemain;

    /* set to 1 once we've started */
    int it_has_begun=0;

    /* the current ui */
    struct chmUnitInfo ui;
    int flag;

    /* the length of the prefix */
    char prefixRectified[CHM_MAX_PATHLEN+1];
    int prefixLen;
    char lastPath[CHM_MAX_PATHLEN];
    int lastPathLen;

    /* starting page */
    curPage = h-&gt;index_head;

    /* initialize pathname state */
    strncpy(prefixRectified, prefix, CHM_MAX_PATHLEN);
    prefixLen = strlen(prefixRectified);
    if (prefixLen != 0)
    {
        if (prefixRectified[prefixLen-1] != '/')
        {
            prefixRectified[prefixLen] = '/';
            prefixRectified[prefixLen+1] = '\0';
            ++prefixLen;
        }
    }
    lastPath[0] = '\0';
    lastPathLen = -1;

    /* until we have either returned or given up */
    while (curPage != -1)
    {

        /* try to fetch the index page */
        if (_chm_fetch_bytes(h,
                             page_buf,
                             (UInt64)h-&gt;dir_offset + (UInt64)curPage*h-&gt;block_len,
                             h-&gt;block_len) != h-&gt;block_len)
            return 0;

        /* figure out start and end for this page */
        cur = page_buf;
        lenRemain = _CHM_PMGL_LEN;
        if (! _unmarshal_pmgl_header(&amp;cur, &amp;lenRemain, &amp;header))
            return 0;
        end = page_buf + h-&gt;block_len - (header.free_space);

        /* loop over this page */
        while (cur &lt; end)
        {
            if (! _chm_parse_PMGL_entry(&amp;cur, &amp;ui))
                return 0;

            /* check if we should start */
            if (! it_has_begun)
            {
                if (ui.length == 0  &amp;&amp;  strncmp(ui.path, prefixRectified, prefixLen) == 0)
                    it_has_begun = 1;
                else
                    continue;

                if (ui.path[prefixLen] == '\0')
                    continue;
            }

            /* check if we should stop */
            else
            {
                if (strncmp(ui.path, prefixRectified, prefixLen) != 0)
                    return 1;
            }

            /* check if we should include this path */
            if (lastPathLen != -1)
            {
                if (strncmp(ui.path, lastPath, lastPathLen) == 0)
                    continue;
            }
            strcpy(lastPath, ui.path);
            lastPathLen = strlen(lastPath);

            /* check for DIRS */
            if (ui.length == 0  &amp;&amp;  !(what &amp; CHM_ENUMERATE_DIRS))
                continue;

            /* check for FILES */
            if (ui.length != 0  &amp;&amp;  !(what &amp; CHM_ENUMERATE_FILES))
                continue;

            /* check for NORMAL vs. META */
            if (ui.path[0] == '/')
            {

                /* check for NORMAL vs. SPECIAL */
                if (ui.path[1] == '#'  ||  ui.path[1] == '$')
                    flag = CHM_ENUMERATE_SPECIAL;
                else
                    flag = CHM_ENUMERATE_NORMAL;
            }
            else
                flag = CHM_ENUMERATE_META;
            if (! (what &amp; flag))
                continue;

            /* call the enumerator */
            {
                int status = (*e)(h, &amp;ui, context);
                switch (status)
                {
                    case CHM_ENUMERATOR_FAILURE:  return 0;
                    case CHM_ENUMERATOR_CONTINUE: break;
                    case CHM_ENUMERATOR_SUCCESS:  return 1;
                    default:                      break;
                }
            }
        }

        /* advance to next page */
        curPage = header.block_next;
    }

    return 1;
}
发表于 2003-8-5 12:47:27 | 显示全部楼层
把错误信息贴出来
回复

使用道具 举报

发表于 2003-8-6 08:36:08 | 显示全部楼层
这个库是干什么的啊?这么多源代码,怎么看??
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

GMT+8, 2025-8-11 14:57 , Processed in 0.033258 second(s), 16 queries .

© 2001-2025 Discuz! Team. Powered by Discuz! X3.5.

快速回复 返回顶部 返回列表