⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fdi.c

📁 winNT技术操作系统,国外开放的原代码和LIUX一样
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 * File Decompression Interface
 *
 * Copyright 2000-2002 Stuart Caie
 * Copyright 2002 Patrik Stridvall
 * Copyright 2003 Greg Turner
 *
 * This library 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.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 *
 *
 * This is a largely redundant reimplementation of the stuff in cabextract.c.  It
 * would be theoretically preferable to have only one, shared implementation, however
 * there are semantic differences which may discourage efforts to unify the two.  It
 * should be possible, if awkward, to go back and reimplement cabextract.c using FDI.
 * But this approach would be quite a bit less performant.  Probably a better way
 * would be to create a "library" of routines in cabextract.c which do the actual
 * decompression, and have both fdi.c and cabextract share those routines.  The rest
 * of the code is not sufficiently similar to merit a shared implementation.
 *
 * The worst thing about this API is the bug.  "The bug" is this: when you extract a
 * cabinet, it /always/ informs you (via the hasnext field of PFDICABINETINFO), that
 * there is no subsequent cabinet, even if there is one.  wine faithfully reproduces
 * this behavior.
 *
 * TODO:
 *
 * Wine does not implement the AFAIK undocumented "enumerate" callback during
 * FDICopy.  It is implemented in Windows and therefore worth investigating...
 *
 * Lots of pointers flying around here... am I leaking RAM?
 *
 * WTF is FDITruncate?
 *
 * Probably, I need to weed out some dead code-paths.
 *
 * Test unit(s).
 *
 * The fdintNEXT_CABINET callbacks are probably not working quite as they should.
 * There are several FIXME's in the source describing some of the deficiencies in
 * some detail.  Additionally, we do not do a very good job of returning the right
 * error codes to this callback.
 *
 * FDICopy and fdi_decomp are incomprehensibly large; separating these into smaller
 * functions would be nice.
 *
 *   -gmt
 */

#include "config.h"

#include <stdarg.h>
#include <stdio.h>

#include "windef.h"
#include "winbase.h"
#include "winerror.h"
#include "fdi.h"
#include "cabinet.h"

#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(cabinet);

THOSE_ZIP_CONSTS;

struct fdi_file {
  struct fdi_file *next;               /* next file in sequence          */
  LPCSTR filename;                     /* output name of file            */
  int    fh;                           /* open file handle or NULL       */
  cab_ULONG length;                    /* uncompressed length of file    */
  cab_ULONG offset;                    /* uncompressed offset in folder  */
  cab_UWORD index;                     /* magic index number of folder   */
  cab_UWORD time, date, attribs;       /* MS-DOS time/date/attributes    */
  BOOL oppressed;                      /* never to be processed          */
};

struct fdi_folder {
  struct fdi_folder *next;
  cab_off_t offset;                    /* offset to data blocks (32 bit) */
  cab_UWORD comp_type;                 /* compression format/window size */
  cab_ULONG comp_size;                 /* compressed size of folder      */
  cab_UBYTE num_splits;                /* number of split blocks + 1     */
  cab_UWORD num_blocks;                /* total number of blocks         */
};

/*
 * this structure fills the gaps between what is available in a PFDICABINETINFO
 * vs what is needed by FDICopy.  Memory allocated for these becomes the responsibility
 * of the caller to free.  Yes, I am aware that this is totally, utterly inelegant.
 * To make things even more unnecessarily confusing, we now attach these to the
 * fdi_decomp_state.
 */
typedef struct {
   char *prevname, *previnfo;
   char *nextname, *nextinfo;
   BOOL hasnext;  /* bug free indicator */
   int folder_resv, header_resv;
   cab_UBYTE block_resv;
} MORE_ISCAB_INFO, *PMORE_ISCAB_INFO;

/*
 * ugh, well, this ended up being pretty damn silly...
 * now that I've conceded to build equivalent structures to struct cab.*,
 * I should have just used those, or, better yet, unified the two... sue me.
 * (Note to Microsoft: That's a joke.  Please /don't/ actually sue me! -gmt).
 * Nevertheless, I've come this far, it works, so I'm not gonna change it
 * for now.  This implementation has significant semantic differences anyhow.
 */

typedef struct fdi_cds_fwd {
  void *hfdi;                      /* the hfdi we are using                 */
  int filehf, cabhf;               /* file handle we are using              */
  struct fdi_folder *current;      /* current folder we're extracting from  */
  cab_ULONG offset;                /* uncompressed offset within folder     */
  cab_UBYTE *outpos;               /* (high level) start of data to use up  */
  cab_UWORD outlen;                /* (high level) amount of data to use up */
  int (*decompress)(int, int, struct fdi_cds_fwd *); /* chosen compress fn  */
  cab_UBYTE inbuf[CAB_INPUTMAX+2]; /* +2 for lzx bitbuffer overflows!       */
  cab_UBYTE outbuf[CAB_BLOCKMAX];
  union {
    struct ZIPstate zip;
    struct QTMstate qtm;
    struct LZXstate lzx;
  } methods;
  /* some temp variables for use during decompression */
  cab_UBYTE q_length_base[27], q_length_extra[27], q_extra_bits[42];
  cab_ULONG q_position_base[42];
  cab_ULONG lzx_position_base[51];
  cab_UBYTE extra_bits[51];
  USHORT  setID;                   /* Cabinet set ID */
  USHORT  iCabinet;                /* Cabinet number in set (0 based) */
  struct fdi_cds_fwd *decomp_cab;
  MORE_ISCAB_INFO mii;
  struct fdi_folder *firstfol; 
  struct fdi_file   *firstfile;
  struct fdi_cds_fwd *next;
} fdi_decomp_state;

/****************************************************************
 * QTMupdatemodel (internal)
 */
void QTMupdatemodel(struct QTMmodel *model, int sym) {
  struct QTMmodelsym temp;
  int i, j;

  for (i = 0; i < sym; i++) model->syms[i].cumfreq += 8;

  if (model->syms[0].cumfreq > 3800) {
    if (--model->shiftsleft) {
      for (i = model->entries - 1; i >= 0; i--) {
    /* -1, not -2; the 0 entry saves this */
    model->syms[i].cumfreq >>= 1;
    if (model->syms[i].cumfreq <= model->syms[i+1].cumfreq) {
      model->syms[i].cumfreq = model->syms[i+1].cumfreq + 1;
    }
      }
    }
    else {
      model->shiftsleft = 50;
      for (i = 0; i < model->entries ; i++) {
    /* no -1, want to include the 0 entry */
    /* this converts cumfreqs into frequencies, then shifts right */
    model->syms[i].cumfreq -= model->syms[i+1].cumfreq;
    model->syms[i].cumfreq++; /* avoid losing things entirely */
    model->syms[i].cumfreq >>= 1;
      }

      /* now sort by frequencies, decreasing order -- this must be an
       * inplace selection sort, or a sort with the same (in)stability
       * characteristics
       */
      for (i = 0; i < model->entries - 1; i++) {
    for (j = i + 1; j < model->entries; j++) {
      if (model->syms[i].cumfreq < model->syms[j].cumfreq) {
        temp = model->syms[i];
        model->syms[i] = model->syms[j];
        model->syms[j] = temp;
      }
    }
      }
    
      /* then convert frequencies back to cumfreq */
      for (i = model->entries - 1; i >= 0; i--) {
    model->syms[i].cumfreq += model->syms[i+1].cumfreq;
      }
      /* then update the other part of the table */
      for (i = 0; i < model->entries; i++) {
    model->tabloc[model->syms[i].sym] = i;
      }
    }
  }
}

/*************************************************************************
 * make_decode_table (internal)
 *
 * This function was coded by David Tritscher. It builds a fast huffman
 * decoding table out of just a canonical huffman code lengths table.
 *
 * PARAMS
 *   nsyms:  total number of symbols in this huffman tree.
 *   nbits:  any symbols with a code length of nbits or less can be decoded
 *           in one lookup of the table.
 *   length: A table to get code lengths from [0 to syms-1]
 *   table:  The table to fill up with decoded symbols and pointers.
 *
 * RETURNS
 *   OK:    0
 *   error: 1
 */
int make_decode_table(cab_ULONG nsyms, cab_ULONG nbits, cab_UBYTE *length, cab_UWORD *table) {
  register cab_UWORD sym;
  register cab_ULONG leaf;
  register cab_UBYTE bit_num = 1;
  cab_ULONG fill;
  cab_ULONG pos         = 0; /* the current position in the decode table */
  cab_ULONG table_mask  = 1 << nbits;
  cab_ULONG bit_mask    = table_mask >> 1; /* don't do 0 length codes */
  cab_ULONG next_symbol = bit_mask; /* base of allocation for long codes */

  /* fill entries for codes short enough for a direct mapping */
  while (bit_num <= nbits) {
    for (sym = 0; sym < nsyms; sym++) {
      if (length[sym] == bit_num) {
        leaf = pos;

        if((pos += bit_mask) > table_mask) return 1; /* table overrun */

        /* fill all possible lookups of this symbol with the symbol itself */
        fill = bit_mask;
        while (fill-- > 0) table[leaf++] = sym;
      }
    }
    bit_mask >>= 1;
    bit_num++;
  }

  /* if there are any codes longer than nbits */
  if (pos != table_mask) {
    /* clear the remainder of the table */
    for (sym = pos; sym < table_mask; sym++) table[sym] = 0;

    /* give ourselves room for codes to grow by up to 16 more bits */
    pos <<= 16;
    table_mask <<= 16;
    bit_mask = 1 << 15;

    while (bit_num <= 16) {
      for (sym = 0; sym < nsyms; sym++) {
        if (length[sym] == bit_num) {
          leaf = pos >> 16;
          for (fill = 0; fill < bit_num - nbits; fill++) {
            /* if this path hasn't been taken yet, 'allocate' two entries */
            if (table[leaf] == 0) {
              table[(next_symbol << 1)] = 0;
              table[(next_symbol << 1) + 1] = 0;
              table[leaf] = next_symbol++;
            }
            /* follow the path and select either left or right for next bit */
            leaf = table[leaf] << 1;
            if ((pos >> (15-fill)) & 1) leaf++;
          }
          table[leaf] = sym;

          if ((pos += bit_mask) > table_mask) return 1; /* table overflow */
        }
      }
      bit_mask >>= 1;
      bit_num++;
    }
  }

  /* full table? */
  if (pos == table_mask) return 0;

  /* either erroneous table, or all elements are 0 - let's find out. */
  for (sym = 0; sym < nsyms; sym++) if (length[sym]) return 1;
  return 0;
}

/*************************************************************************
 * checksum (internal)
 */
cab_ULONG checksum(cab_UBYTE *data, cab_UWORD bytes, cab_ULONG csum) {
  int len;
  cab_ULONG ul = 0;

  for (len = bytes >> 2; len--; data += 4) {
    csum ^= ((data[0]) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24));
  }

  switch (bytes & 3) {
  case 3: ul |= *data++ << 16;
  case 2: ul |= *data++ <<  8;
  case 1: ul |= *data;
  }
  csum ^= ul;

  return csum;
}

/***********************************************************************
 *		FDICreate (CABINET.20)
 *
 * Provided with several callbacks (all of them are mandatory),
 * returns a handle which can be used to perform operations
 * on cabinet files.
 *
 * PARAMS
 *   pfnalloc [I]  A pointer to a function which allocates ram.  Uses
 *                 the same interface as malloc.
 *   pfnfree  [I]  A pointer to a function which frees ram.  Uses the
 *                 same interface as free.
 *   pfnopen  [I]  A pointer to a function which opens a file.  Uses
 *                 the same interface as _open.
 *   pfnread  [I]  A pointer to a function which reads from a file into
 *                 a caller-provided buffer.  Uses the same interface
 *                 as _read
 *   pfnwrite [I]  A pointer to a function which writes to a file from
 *                 a caller-provided buffer.  Uses the same interface
 *                 as _write.
 *   pfnclose [I]  A pointer to a function which closes a file handle.
 *                 Uses the same interface as _close.
 *   pfnseek  [I]  A pointer to a function which seeks in a file.
 *                 Uses the same interface as _lseek.
 *   cpuType  [I]  The type of CPU; ignored in wine (recommended value:
 *                 cpuUNKNOWN, aka -1).
 *   perf     [IO] A pointer to an ERF structure.  When FDICreate
 *                 returns an error condition, error information may
 *                 be found here as well as from GetLastError.
 *
 * RETURNS
 *   On success, returns an FDI handle of type HFDI.
 *   On failure, the NULL file handle is returned. Error
 *   info can be retrieved from perf.
 *
 * INCLUDES
 *   fdi.h
 * 
 */
HFDI __cdecl FDICreate(
	PFNALLOC pfnalloc,
	PFNFREE  pfnfree,
	PFNOPEN  pfnopen,
	PFNREAD  pfnread,
	PFNWRITE pfnwrite,
	PFNCLOSE pfnclose,
	PFNSEEK  pfnseek,
	int      cpuType,
	PERF     perf)
{
  HFDI rv;

  TRACE("(pfnalloc == ^%p, pfnfree == ^%p, pfnopen == ^%p, pfnread == ^%p, pfnwrite == ^%p, \
        pfnclose == ^%p, pfnseek == ^%p, cpuType == %d, perf == ^%p)\n", 
        pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose, pfnseek,
        cpuType, perf);

  if ((!pfnalloc) || (!pfnfree)) {
    perf->erfOper = FDIERROR_NONE;
    perf->erfType = ERROR_BAD_ARGUMENTS;
    perf->fError = TRUE;

    SetLastError(ERROR_BAD_ARGUMENTS);
    return NULL;
  }

  if (!((rv = ((HFDI) (*pfnalloc)(sizeof(FDI_Int)))))) {
    perf->erfOper = FDIERROR_ALLOC_FAIL;
    perf->erfType = ERROR_NOT_ENOUGH_MEMORY;
    perf->fError = TRUE;

    SetLastError(ERROR_NOT_ENOUGH_MEMORY);
    return NULL;
  }
  

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -