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

📄 pdbfile.cpp

📁 俄罗斯人开发的大名鼎鼎的Pocket Pc 阅读器haaliread的源代码,visual c
💻 CPP
字号:
/*
 * Copyright (c) 2001,2002,2003 Mike Matsnev.  All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice immediately at the beginning of the file, without modification,
 *    this list of conditions, and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Absolutely no warranty of function or purpose is made by the author
 *    Mike Matsnev.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * $Id: PDBFile.cpp,v 1.13.2.5 2004/09/29 08:27:12 mike Exp $
 * 
 */

#include <afxwin.h>

#include "ptr.h"
#include "PDBFile.h"
#include "TextViewNG.h"

#include <string.h>

// pdb header
struct PDBHdr {
  char	  name[32];
  WORD	  attr;
  WORD	  ver;
  DWORD	  ctime;
  DWORD	  mtime;
  DWORD	  btime;
  DWORD	  mnum;
  DWORD	  appinfoid;
  DWORD	  aortinfoid;
  char	  type[4];
  char	  creator[4];
  DWORD	  idseed;
  DWORD	  nextreclist;
  WORD	  numrec;
};
#define	PDBHDRSIZE  78

// record 0
struct PDBRec0 {
  WORD	  ver;
  WORD	  res1;
  DWORD	  usize;
  WORD	  nrec;
  WORD	  rsize;
  DWORD	  res2;
};
#define	PDBR0SIZE 16

static DWORD  dword(const DWORD& dw) { // convert from BE
  BYTE	*b=(BYTE*)&dw;
  return ((DWORD)b[0]<<24)|((DWORD)b[1]<<16)|((DWORD)b[2]<<8)|b[3];
}

static WORD   word(const WORD& w) { // convert from BE
  BYTE	*b=(BYTE*)&w;
  return ((WORD)b[0]<<8)|b[1];
}

bool  PDBFile::CheckPDB(RFile *fp,PDBHdr& hdr,PDBRec0& r0) {
  // we want to access original RFile methods, not the overridden
  // ones
  fp->RFile::seek(0);
  if (fp->RFile::read2(&hdr,PDBHDRSIZE)!=PDBHDRSIZE)
    return false;
  if (memcmp(hdr.type,"TEXt",4) || memcmp(hdr.creator,"REAd",4))
    return false;
  DWORD	  off0;
  if (fp->RFile::read2(&off0,4)!=4)
    return false;
  fp->RFile::seek(dword(off0));
  if (fp->RFile::read2(&r0,PDBR0SIZE)!=PDBR0SIZE)
    return false;
  if (word(r0.ver)!=1 && word(r0.ver)!=2 && word(r0.ver)!=257 && word(r0.nrec)>0)
    return false;
  return true;
}

static DWORD	scan_size(BYTE *src,DWORD len) {
  DWORD	  ulen=0;

  while (len--) {
    if (*src>=1 && *src<=8) {
      DWORD k=*src++;
      while (k-- && len--)
	src++,ulen++;
    } else if (*src<=0x7f)
      src++,ulen++;
    else if (*src>=0xc0)
      src++,ulen+=2;
    else if (len) {
      DWORD k=*src++;
      k<<=8; k|=*src++;
      --len;
      ulen+=(k&7)+3;
    }
  }
  return ulen;
}

PDBFile::PDBFile(const CString& fn) :
  RFile(fn), m_length(0), m_ptr(0)
{
  PDBHdr    hdr;
  PDBRec0   r0;
  if (Reopen() && CheckPDB(this,hdr,r0)) {
    m_comp=word(r0.ver)==2;
    m_rsz=word(r0.rsize);
    DWORD nr=word(r0.nrec);
    m_blocks=Buffer<Rec>(nr);
    // fill in records table
    RFile::seek(PDBHDRSIZE+8);
    for (DWORD j=0;j<nr;++j) {
      DWORD   off[2];
      if (RFile::read2(off,8)!=8)
	goto fail;
      m_blocks[j].off=dword(off[0]);
      if (j>0) {
	m_blocks[j-1].csize=m_blocks[j].off-m_blocks[j-1].off;
	if (m_blocks[j-1].csize>m_rsz)
	  goto fail;
      }
    }
    if (nr+1<word(hdr.numrec)) { // minus rec0
      DWORD   off[2];
      if (RFile::read2(off,8)!=8)
	goto fail;
      m_blocks[nr-1].csize=dword(off[0])-m_blocks[nr-1].off;
    } else
      m_blocks[nr-1].csize=(DWORD)RFile::size()-m_blocks[nr-1].off;
    if (m_blocks[nr-1].csize>m_rsz)
      goto fail;
    if (m_comp) { // compressed
      Buffer<BYTE>  tmp(m_rsz);
      DWORD	    uoff=0;
      for (int i=0;i<m_blocks.size();++i) {
	RFile::seek(m_blocks[i].off);
	if (RFile::read2(tmp,m_blocks[i].csize)!=m_blocks[i].csize)
	  goto fail;
	m_blocks[i].usize=scan_size(tmp,m_blocks[i].csize);
	if (m_blocks[i].usize>m_rsz)
	  goto fail;
	m_blocks[i].uoff=uoff;
	uoff+=m_blocks[i].usize;
      }
      m_length=uoff;
    } else { // uncompressed
      for (int i=0;i<m_blocks.size();++i) {
	m_blocks[i].usize=m_blocks[i].csize;
	m_blocks[i].uoff=m_length;
	m_length+=m_blocks[i].usize;
      }
    }
    return;
  }
fail:
  CTVApp::Barf(_T("Invalid or unsupported PDB file"));
}

static DWORD	pdb_decompress(BYTE *source,DWORD srclen,BYTE *dest,DWORD destlen)
{
  BYTE	    *se=source+srclen;
  BYTE	    *de=dest+destlen;
  BYTE	    *dd=dest;

  while (source<se && dest<de) {
    DWORD c=*source++;
    if (c>=1 && c<=8) { // copy
      while (c-- && source<se && dest<de)
	*dest++=*source++;
    } else if (c<=0x7f) // this char
      *dest++=(BYTE)c;
    else if (c>=0xc0) { // space + c&0x7f
      *dest++=' ';
      if (dest<de)
	*dest++=(BYTE)c&0x7f;
    } else if (source<se) { // copy from decoded buf
      c=(c<<8)|*source++;
      int k=(c&0x3fff)>>3;
      c=3+(c&7);
      if (dest-k<dd || dest+c>de) // invalid buffer
	break;
      while (c-- && dest<de) {
	*dest=dest[-k];
	++dest;
      }
    }
  }
  return dest-dd;
}

void  PDBFile::seek(DWORD pos) {
  if (pos>=m_length)
    m_ptr=m_length;
  else
    m_ptr=pos&BMASK;
}

DWORD PDBFile::read(void *buf) {
  if (m_ptr>=m_length)
    return 0;
  // ok, figure what block is needed
  int i;
  for (i=0;i<m_blocks.size();++i)
    if (m_ptr>=m_blocks[i].uoff && m_ptr<m_blocks[i].uoff+m_blocks[i].usize)
      goto found;
  return 0;
found:
  Buffer<BYTE>	  tmp(m_rsz),tmp2(m_rsz);
  BYTE		  *p=(BYTE*)buf;
  DWORD		  n=BSZ;
  while (i<m_blocks.size() && n>0) {
    RFile::seek(m_blocks[i].off);
    if (m_comp) {
      if (RFile::read2(tmp2,m_blocks[i].csize)!=m_blocks[i].csize)
	return 0;
      if (pdb_decompress(tmp2,m_blocks[i].csize,tmp,m_rsz)!=m_blocks[i].usize)
	return 0;
    } else {
      if (RFile::read2(tmp,m_blocks[i].csize)!=m_blocks[i].csize)
	return 0;
    }
    // now we have a decompressed block in tmp
    DWORD   hb=m_blocks[i].uoff+m_blocks[i].usize-m_ptr;
    if (hb>n)
      hb=n;
    memcpy(p,tmp+m_ptr-m_blocks[i].uoff,hb);
    p+=hb;
    m_ptr+=hb;
    n-=hb;
    ++i;
  }
  return BSZ-n;
}

CString PDBFile::CompressionInfo() {
  if (m_comp && m_length>0) {
    CString ret;
    ret.Format(_T("PDB, packed (%.2f)"),
      (double)RFile::size()/(double)m_length);
    return ret;
  }
  return _T("PDB, not packed");
}

bool  PDBFile::IsPDB(RFile *fp) {
  PDBHdr    hdr;
  PDBRec0   r0;
  bool ret=CheckPDB(fp,hdr,r0);
  fp->seek(0);
  return ret;
}

⌨️ 快捷键说明

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