/* * Zio.cpp * EBLib2 * * Created by hishida on 08/12/22. * Copyright 2008 __MyCompanyName__. All rights reserved. * */ // Zio.cpp: CZio クラスのインプリメンテーション // ////////////////////////////////////////////////////////////////////// // 2004/7/25 //#if defined(_MSC_VER) #include "stdafx.h" //#else //#include "common.h" //#endif #include "Zio.h" #include "zlib.h" #include "EBUtil.h" // コンパイル時:zlib.h zconf.h libz.def libz.lib が必要 // 実行時 :zlib.dll /*#ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[]=__FILE__; #define new DEBUG_NEW #endif */ #define FRAMESIZE 2048 // EB/EPWINGのページ長 //#define _MAXIOBUF 16*1024 // setvbuf()を使用する場合のバッファサイズ #define TWOBYTEUINT(b) ((((unsigned int)*(b))<<8) + ((unsigned int)*((b) +1))) #define FOURBYTEUINT(b) \ ((((unsigned int)*((b)+0))<<24) + (((unsigned int)*((b)+1))<<16) + \ (((unsigned int)*((b)+2))<<8) + (((unsigned int)*((b)+3))<<0 )) ////////////////////////////////////////////////////////////////////// // zlibを利用した伸長(ebzip用) ////////////////////////////////////////////////////////////////////// #define INBUFSIZ 1024 /* 入力バッファサイズ(任意) */ z_stream z; /* ライブラリとやりとりするための構造体 */ unsigned char inbuf[INBUFSIZ]; /* 入力バッファ */ // finの現在位置から length バイトを伸長する int decompress( FILE *fin, // ファイルポインタ(現在位置から読む) int srclen, // 伸長前の長さ unsigned char *outbuf, // 出力バッファ int dstlen ) // 出力バッファの長さ { int status; /* すべてのメモリ管理をライブラリに任せる */ z.zalloc = Z_NULL; z.zfree = Z_NULL; z.opaque = Z_NULL; /* 初期化 */ z.next_in = Z_NULL; z.avail_in = 0; if (inflateInit(&z) != Z_OK) { #if defined(_WIN32_WCE_PSPC) && (_WIN32_WCE < 212) #else fprintf(stderr, "inflateInit: %s\n", (z.msg) ? z.msg : "???"); #endif exit(1); } z.next_out = outbuf; /* 出力ポインタ */ z.avail_out = dstlen; /* 出力バッファ残量 */ status = Z_OK; int readcount = 0; while (status != Z_STREAM_END) { if (z.avail_in == 0) { /* 入力残量がゼロになれば */ z.next_in = inbuf; /* 入力ポインタを元に戻す */ z.avail_in = fread(inbuf, 1, INBUFSIZ, fin); /* データを読む */ readcount += z.avail_in ; } status = inflate(&z, Z_NO_FLUSH); /* 展開 */ if (status == Z_STREAM_END) break; /* 完了 */ if (status != Z_OK) { /* エラー */ #if defined(_WIN32_WCE_PSPC) && (_WIN32_WCE < 212) #else fprintf(stderr, "inflate: %s\n", (z.msg) ? z.msg : "???"); #endif return 0; } if (z.avail_out == 0) { /* 出力バッファが尽きれば */ break; } } readcount -= z.avail_in; /* 後始末 */ if (inflateEnd(&z) != Z_OK) { #if defined(_WIN32_WCE_PSPC) && (_WIN32_WCE < 212) #else fprintf(stderr, "inflateEnd: %s\n", (z.msg) ? z.msg : "???"); #endif return 0; } return readcount; } ////////////////////////////////////////////////////////////////////// // 構築/消滅 ////////////////////////////////////////////////////////////////////// CZio::CZio() { memset( &m_info, 0, sizeof(ZIO_Info) ); m_callback = NULL; m_pszFileName[0] = '\0'; } CZio::~CZio() { zClose(); } // ファイルのオープン // 正常時0,エラーは-1を返す int CZio::zOpen(LPCTSTR filename, int EPVer) // EPWING Ver 0:不明 // 4:V4/5 // 6:V6 { unsigned char head[32]; // ebzipとEPWINGのヘッダ部が保持できる領域長とする memset( &m_info, 0, sizeof(ZIO_Info) ); // 共通部の初期化 m_info.blkno = 1; // 現在のブロック番号 m_info.type = COMP_NONE; // まず非圧縮に設定 #if defined(_MSC_VER) m_info.fp = _tfopen( filename, _T("rb") ); #else m_info.fp = _tfopen( filename, _T("r") ); #endif if ( m_info.fp == NULL ) return -1; // error _tcsncpy( (TCHAR*)m_pszFileName, filename, _MAX_PATH); /* #if !defined(_WIN32_WCE) if ( setvbuf( m_info.fp, NULL, _IOFBF, _MAXIOBUF ) != 0 ) return -1; // error #endif */ // ヘッダ部を走査し、ebzip形式かどうか判定 if ( fread( head,1,32,m_info.fp ) != 32 ) { return -1; } // ファイルサイズ if ( fseeko( m_info.fp, 0, SEEK_END ) != 0 ) { return -1; } m_info.fileSize = ftello( m_info.fp ); // 以下、圧縮形式用の初期化 int ix; for ( ix=0;ix>4; m_info.zipLevel = head[5] & 0x0F; ASSERT( m_info.zipMode == 1|| m_info.zipMode == 2); ASSERT( m_info.zipLevel >=0 && m_info.zipLevel<6); #if defined(_WIN32_WCE) && !defined(USE_CE64BIT) || !defined(_MSC_VER) // WindowsCEの場合、圧縮レベルに合わせてスライスバッファ個数を可変にする if ( m_info.zipLevel == 0 ) m_info.maxSlice = MAX_SLICE_BUF<<3; else if ( m_info.zipLevel == 1 ) m_info.maxSlice = MAX_SLICE_BUF<<2; else if ( m_info.zipLevel == 2 ) m_info.maxSlice = MAX_SLICE_BUF<<1; else /* >= 3*/ m_info.maxSlice = MAX_SLICE_BUF; #else m_info.maxSlice = MAX_SLICE_BUF; #endif // 非圧縮時のファイルサイズ m_info.orgSize = ((off_t)head[8] << 8*5) + ((off_t)head[9] << 8*4) + ((off_t)head[10] << 8*3) + ((off_t)head[11] << 8*2) + ((off_t)head[12] << 8) + ((off_t)head[13] ); // インデックスの大きさ if ( m_info.orgSize< 65536 ) m_info.idxSize = 2; else if ( m_info.orgSize<= 16777215 ) m_info.idxSize = 3; #if defined(_MSC_VER) else if ( m_info.orgSize<= 4294967295 ) #else else if ( m_info.orgSize<= 4294967295LL ) #endif m_info.idxSize = 4; else m_info.idxSize = 5; // Adler-32によるチェックサム m_info.CheckSum = ((off_t)head[14] << 8*3) + ((off_t)head[15] << 8*2) + ((off_t)head[16] << 8) + ((off_t)head[17]) ; // スライス長 m_info.sliceSize = FRAMESIZE<m_info.fileSize ) { // 圧縮形式ではないので、非圧縮と見なす m_info.type = COMP_NONE; m_info.orgSize = m_info.fileSize; } else { if ( EPVer == 4 || EPVer == 5 ) { m_info.type = COMP_EPV4; } else if ( EPVer == 6 ) { m_info.type = COMP_EPV6; } else { // EPWING Verが指定されなかった場合 m_info.type = COMP_EPV6; } // 伸長後のサイズを求める unsigned char buff[36]; if ( fseek( m_info.fp,m_info.epwHdr.freqOffs-36,SEEK_SET ) == 0 && fread( buff,1,36,m_info.fp ) == 36 ) { m_info.orgSize = ( m_info.epwHdr.idxLen / 36 ) * 16 * 2048; for ( int pos=4+2;pos<36;pos+=2 ) { if ( TWOBYTEUINT(buff+pos)==0 ) m_info.orgSize -= 2048; } } m_info.maxSlice = MAX_EPW_BUF; m_info.bInitiate = FALSE; } } zSeekBlk(1); return 0; } // ファイルのクローズ void CZio::zClose() { // ebzip スライスバッファがあれば開放 int ix; for ( ix=0;ix スライス番号(0..) #define SLICE_NO(blk) (((off_t)(blk-1)*FRAMESIZE)/m_info.sliceSize) #define SEBXA_SLICE_NO(blk) (((blk-m_info.sinfo.honBlkTop)*FRAMESIZE)/m_info.sliceSize) // 指定したブロック番号(1origin)にseekする // 正常時0,エラーは-1を返す int CZio::zSeekBlk(unsigned int blk) { ASSERT( blk>0 ); m_info.blkno = blk; if ( blk == 0 ) return -1; if ( m_info.type == COMP_NONE ) { // 一般ファイル ASSERT( m_info.fp ); return fseeko( m_info.fp, (off_t)(blk-1)*FRAMESIZE, SEEK_SET ); } else if ( m_info.type == COMP_EBZIP ) { // 特にすることはない return 0; } else if ( m_info.type == COMP_EPV4 || m_info.type == COMP_EPV6 ) { // 特にすることはない return 0; } else if ( m_info.type == COMP_SEBXA ) { // 特にすることはない return 0; } #if defined(_SSED_SUPPORT) else if ( m_info.type == COMP_SSED ) { // 特にすることはない return 0; } #endif return -1; } // Seekで用意したバッファから、2048ブロック読む // 戻り値は読み出したバイト数(0なら失敗) int CZio::zReadBlk( unsigned char *data ) { ASSERT( m_info.fp ); ASSERT( m_info.blkno > 0 ); unsigned int blk = m_info.blkno; // 2009/03/07 BOOL bHit = FALSE; unsigned char buf[256]; int n = 0; // 読み込んだバイト数 if ( m_info.blkno < 1 ) goto do_err; // if ( m_info.orgSize>0 && // (m_info.orgSize+FRAMESIZE-1)/FRAMESIZE < (size_t)m_info.blkno ) // goto do_err; if ( m_info.type == COMP_NONE ) { // 非圧縮 int nread = fread( data, 1,FRAMESIZE,m_info.fp ) ; if ( nread <= 0) { n = 0; } else { if ( nread=m_info.n_element ) { memset( data, 0, FRAMESIZE ); n = FRAMESIZE; goto do_ok; } // 交代バッファにスライスが読込済みかどうか確認 bHit = FALSE; for ( int ix=0; ix0 && m_info.extinfo[idxno].start == m_info.startBlk[ix] && (((blk-m_info.extinfo[idxno].start)*FRAMESIZE)/SSED_SLICE_SIZE) == (((m_info.curBlk[ix] - m_info.startBlk[ix])*FRAMESIZE)/SSED_SLICE_SIZE) ) { // 注意:LogoVistaは書籍構成要素が別ファイルに分かれているため、ブロック番号が // 隣接していても、別ファイルの場合はキャッシュにはない m_info.ixbuf = ix; bHit = TRUE; } } if ( !bHit ) { // 交代バッファのなかにスライスがないので読み込む // 保存する交代バッファを決める ++m_info.ixbuf; if ( m_info.ixbuf>=m_info.maxSlice ) { m_info.ixbuf = 0; // 交代バッファを循環させる } if ( SSED_decode(blk,&m_info.extinfo[idxno],m_info.pSlice[m_info.ixbuf],SSED_SLICE_SIZE) == 0 ) { goto do_err; } } ASSERT(m_info.ixbuf0 && SLICE_NO(blk) == SLICE_NO(m_info.curBlk[ix] ) ) { m_info.ixbuf = ix; bHit = TRUE; break; // 2004/09/26 } } if ( !bHit ) { // 交代バッファのなかにスライスがないので読み込む // 保存する交代バッファを決める ++m_info.ixbuf; if ( m_info.ixbuf>=m_info.maxSlice ) { m_info.ixbuf = 0; // 交代バッファを循環させる } // インデックス読み込み off_t fromOffs,toOffs; #if defined(USE_EBZIP_RESIDENT_INDEX) if ( !m_info.idxTbl ) { // 常駐インデックスをまだ読み込んでいなければ読み込み ASSERT( m_info.dataOffs>EBZ_HEAD_LEN ); m_info.idxTbl = (unsigned char *)malloc(m_info.dataOffs-EBZ_HEAD_LEN); if ( fseeko( m_info.fp, (off_t) EBZ_HEAD_LEN, SEEK_SET ) == 0 ) { if ( fread( m_info.idxTbl,1, m_info.dataOffs-EBZ_HEAD_LEN, m_info.fp ) != m_info.dataOffs-EBZ_HEAD_LEN ) { goto do_err; } } else { goto do_err; } } off_t idxOffs = SLICE_NO(blk)*m_info.idxSize; ASSERT( idxOffs>=0 && (size_t)idxOffs= m_info.dataOffs-EBZ_HEAD_LEN ) goto do_err; unsigned char *pBuf = m_info.idxTbl+idxOffs; if ( m_info.idxSize == 2 ) { fromOffs = (pBuf[0]<<8)+pBuf[1]; toOffs = (pBuf[2]<<8)+pBuf[3]; } else if ( m_info.idxSize == 3 ) { fromOffs = (pBuf[0]<<8*2)+(pBuf[1]<<8)+pBuf[2]; toOffs = (pBuf[3]<<8*2)+(pBuf[4]<<8)+pBuf[5]; } else if ( m_info.idxSize == 4 ) { fromOffs = ((off_t)pBuf[0]<<8*3)+((off_t)pBuf[1]<<8*2)+((off_t)pBuf[2]<<8)+(off_t)pBuf[3]; toOffs = ((off_t)pBuf[4]<<8*3)+((off_t)pBuf[5]<<8*2)+((off_t)pBuf[6]<<8)+(off_t)pBuf[7]; } else if ( m_info.idxSize == 5 ) { fromOffs = ((off_t)pBuf[0]<<8*4)+((off_t)pBuf[1]<<8*3)+((off_t)pBuf[2]<<8*2)+((off_t)pBuf[3]<<8)+(off_t)pBuf[4]; toOffs = ((off_t)pBuf[5]<<8*4)+((off_t)pBuf[6]<<8*3)+((off_t)pBuf[7]<<8*2)+((off_t)pBuf[8]<<8)+(off_t)pBuf[9]; } #else off_t idxOffs = EBZ_HEAD_LEN+SLICE_NO(blk)*m_info.idxSize; ASSERT( idxOffs>=EBZ_HEAD_LEN && idxOffs= m_info.dataOffs ) goto do_err; if ( fseeko( m_info.fp, (off_t)idxOffs, SEEK_SET ) == 0 ) { fread( buf,1, m_info.idxSize*2, m_info.fp ); } else goto do_err; if ( m_info.idxSize == 2 ) { fromOffs = (buf[0]<<8)+buf[1]; toOffs = (buf[2]<<8)+buf[3]; } else if ( m_info.idxSize == 3 ) { fromOffs = (buf[0]<<8*2)+(buf[1]<<8)+buf[2]; toOffs = (buf[3]<<8*2)+(buf[4]<<8)+buf[5]; } else if ( m_info.idxSize == 4 ) { fromOffs = ((off_t)buf[0]<<8*3)+((off_t)buf[1]<<8*2)+((off_t)buf[2]<<8)+(off_t)buf[3]; toOffs = ((off_t)buf[4]<<8*3)+((off_t)buf[5]<<8*2)+((off_t)buf[6]<<8)+(off_t)buf[7]; } else if ( m_info.idxSize == 5 ) { fromOffs = ((off_t)buf[0]<<8*4)+((off_t)buf[1]<<8*3)+((off_t)buf[2]<<8*2)+((off_t)buf[3]<<8)+(off_t)buf[4]; toOffs = ((off_t)buf[5]<<8*4)+((off_t)buf[6]<<8*3)+((off_t)buf[7]<<8*2)+((off_t)buf[8]<<8)+(off_t)buf[9]; } #endif if ( fromOffs >= m_info.fileSize ) { fromOffs = m_info.fileSize; } if ( toOffs >= m_info.fileSize ) { toOffs = m_info.fileSize; } ASSERT( toOffs>=fromOffs); ASSERT( fromOffs<=m_info.fileSize ); ASSERT( toOffs<=m_info.fileSize ); if ( (toOffs - fromOffs) == m_info.sliceSize ) { // 非圧縮のブロック fseeko( m_info.fp, (off_t)fromOffs, SEEK_SET ); fread( m_info.pSlice[m_info.ixbuf], m_info.sliceSize, 1, m_info.fp ); #ifdef _DEBUG CString s; s.Format(_T("uncompressed:blk=%d(%d)\n"),blk,m_info.sliceSize); TRACE(s); #endif } else { // 圧縮ブロック fseeko( m_info.fp, (off_t)fromOffs, SEEK_SET ); #ifdef _DEBUG CString s; s.Format(_T("inflate:blk=%d(%d)\n"),blk,m_info.sliceSize); // TRACE(s); #endif // zlibを使用して伸長する decompress( m_info.fp, toOffs - fromOffs, m_info.pSlice[m_info.ixbuf], m_info.sliceSize ); } } ASSERT(m_info.ixbuf0 && blk == m_info.curBlk[ix] ) { m_info.ixbuf = ix; bHit = TRUE; break; } } if ( !bHit ) { // バッファキャッシュのなかにバッファがないので読み込む // 保存するバッファ位置を決める ++m_info.ixbuf; if ( m_info.ixbuf>=m_info.maxSlice ) { m_info.ixbuf = 0; // バッファを循環させる } m_info.curBlk[m_info.ixbuf] = blk; // 圧縮ブロック開始位置を得る size_t blkOffs = page2Physical( blk ); if ( blkOffs == -1 ) goto do_err; if ( fseek( m_info.fp, blkOffs, SEEK_SET) != 0 ) goto do_err; #ifdef _DEBUG CString s; s.Format(_T("EPWING:blk=%d offs=%d\n"),blk,blkOffs); TRACE(s); #endif // EPWING V6圧縮なら圧縮種別を読む if ( m_info.type == COMP_EPV6 ) { if ( fread( buf, 1, 1, m_info.fp ) != 1 ) goto do_err; if ( buf[0] != 0x00) { // 非圧縮ブロックを読む int nread = fread( m_info.pSlice[m_info.ixbuf], 1, FRAMESIZE, m_info.fp); if ( nread != FRAMESIZE ) { goto do_err; } n = FRAMESIZE; memcpy( data, m_info.pSlice[m_info.ixbuf], FRAMESIZE ); goto do_ok; } // 圧縮ブロックを伸長する EP_decode( m_info.pSlice[m_info.ixbuf], m_info.sliceSize ); } else { EP_decode( m_info.pSlice[m_info.ixbuf], m_info.sliceSize ); } } ASSERT(m_info.ixbuf m_info.sinfo.honBlkTop+m_info.sinfo.honBlks-1 ) { n = 0; // 圧縮本文の範囲でなければ、非圧縮ブロック if ( fseek( m_info.fp, (blk-1)*FRAMESIZE, SEEK_SET ) == 0 ) { int nread = fread( data, 1,FRAMESIZE,m_info.fp ) ; if ( nread > 0 ) { if ( nread0 && SEBXA_SLICE_NO(blk) == SEBXA_SLICE_NO(m_info.curBlk[ix] ) ) { m_info.ixbuf = ix; bHit = TRUE; break; } } if ( !bHit ) { // 交代バッファのなかにスライスがないので読み込む // 保存する交代バッファを決める size_t fromOffs,toOffs; ++m_info.ixbuf; if ( m_info.ixbuf>=m_info.maxSlice ) { m_info.ixbuf = 0; // 交代バッファを循環させる } // インデックス読み込み #if defined(USE_SEBXA_RESIDENT_INDEX) int iSliceNo = SEBXA_SLICE_NO(blk); ASSERT(iSliceNo>=0 && iSliceNo=fromOffs); if ( toOffs0 ) ++m_info.blkno; return n; do_err: memset( data,0,FRAMESIZE ); return 0; // 失敗 } ////////////////////////////////////////////////////////////////////////// // EPWING V4/V6 ////////////////////////////////////////////////////////////////////////// // 頻度表の読込 TreeNode* CZio::EP_readFreqTable() { TreeNode *pNode = NULL; int ent8,ent16,ent32,nent,top; unsigned char buf[8]; m_info.nNode = 0; m_info.maxNode = 0; m_info.node = NULL; if ( m_info.type == COMP_EPV6 ) { ent8 = 256; ent16 = 1024; ent32 = ((int)m_info.epwHdr.freqLen - (1024 * 4) - (256 * 2)) / 6; } else if ( m_info.type == COMP_EPV4 ) { ent8 = 256; ent16 = ((int)m_info.epwHdr.freqLen - (256 * 2)) / 4; ent32 = 0; } else { return NULL; // EPWING圧縮ではない } nent = (ent32 + ent16 + ent8 + 1) * 2 - 1; if ( ( pNode = (TreeNode *)malloc(sizeof(TreeNode) * nent)) == NULL) goto err; if ( fseek( m_info.fp, m_info.epwHdr.freqOffs, SEEK_SET ) != 0 ) goto err; // ノードを初期化 int i; for ( i = 0; i < m_info.maxNode; i++) { pNode[i].left = 0; pNode[i].right = 0; } // 32ビット頻度表 top = 0; for (i = 0; i < ent32; i++ ) { if ( fread((char *)buf, 1, 6, m_info.fp ) != 6 ) goto err; memcpy(pNode[top].data, buf, 4); pNode[top].freq = (int)TWOBYTEUINT(&buf[4]); pNode[top].type = NODE_LEAF32; top++; } // 16ビット頻度表 for (i = 0; i < ent16; i++) { if (fread((char *)buf, 1, 4, m_info.fp ) != 4) goto err; memcpy(pNode[top].data, buf, 2); pNode[top].freq = (int)TWOBYTEUINT(&buf[2]); pNode[top].type = NODE_LEAF16; top++; } // 8ビット頻度表 for (i = 0; i < ent8; i++) { if (fread((char *)buf, 1, 2, m_info.fp ) != 2) goto err; pNode[top].data[0] = (byte)i; pNode[top].freq = (int)TWOBYTEUINT(buf); pNode[top].type = NODE_LEAF8; top++; } // 終端ノード pNode[top].freq = (int)1; pNode[top].type = NODE_EOD; top++; m_info.maxNode = nent; m_info.nNode = top; m_info.node = pNode; return pNode; err: if ( pNode ) free( pNode ); return NULL; } // 頻度表をソート(選択ソート) void CZio::EP_sortTable() { TreeNode temp; int i,j,imax; for ( i = 0; i < m_info.nNode - 1; i++ ) { imax = i; for ( j = i; j < m_info.nNode; j++ ) { if (m_info.node[j].freq > m_info.node[imax].freq) { imax = j; } } temp = m_info.node[i]; m_info.node[i] = m_info.node[imax]; m_info.node[imax] = temp; } } // ハフマン木の作成 void CZio::EP_makeTree() { int left,right,freq; int iRoot = 0; for (;;) { // 最も小さいノードを探す left = -1; // 未定 freq = 0x7fffffff; // intの最大値 int i; for ( i = 0; i < m_info.nNode; i++) { // 親の決まったノード(頻度=0)はスキップ if (m_info.node[i].freq == 0) continue; if (m_info.node[i].freq <= freq) { freq = m_info.node[i].freq; left = i; } } // 次に小さいノードを探す right = -1; // 未定 freq = 0x7fffffff; // intの最大値 for ( i = 0; i < m_info.nNode; i++) { // 左ノードと親の決まったノード(頻度=0)はスキップ if ( i == left || m_info.node[i].freq == 0) continue; if ( m_info.node[i].freq <= freq) { freq = m_info.node[i].freq; right = i; } } if ( right == -1 ) { // 構築完了 break; } // 新しいノードを作る m_info.node[m_info.nNode].type = NODE_INT; // 中間ノード m_info.node[m_info.nNode].left = left; m_info.node[m_info.nNode].right = right; m_info.node[m_info.nNode].freq = m_info.node[left].freq + m_info.node[right].freq; m_info.node[left].freq = 0; // 親が決定した m_info.node[right].freq = 0; iRoot = m_info.nNode; m_info.nNode++; } } // ビット単位の入力 BOOL CZio::GetBit() { BOOL res; if (m_info.bitCount < 0) { if ( m_info.epwbufptr >= m_info.epwbuf+EPW_SLICE_SIZE-1 ) { m_info.epwbufptr = m_info.epwbuf; fread( m_info.epwbuf,1,EPW_SLICE_SIZE, m_info.fp ); } else ++m_info.epwbufptr; res = ( (*m_info.epwbufptr) >> 7 ) & 1; m_info.bitCount = 6; } else res = ( (*m_info.epwbufptr) >> m_info.bitCount-- ) & 1; return res; } ///////////////////////////////////////////////////////////////// //#define GETBIT() \ // (m_info.bitCount<0 \ // ? m_info.bitCount=6,(*++m_info.epwbuf >> 7) & 1 \ // : (*m_info.epwbuf >> m_info.bitCount--) & 1 ) ///////////////////////////////////////////////////////////////// // ハフマン圧縮を伸長する int CZio::EP_decode( unsigned char *pDst, int oMax ) { ASSERT( m_info.fp ); ASSERT( m_info.epwbuf ); // GetBit()の初期化 << m_info.bitCount = -1; m_info.epwbufptr = m_info.epwbuf+EPW_SLICE_SIZE; // >> unsigned char* p = pDst; unsigned char* pend = &pDst[oMax]; int j; while (p < pend) { j = m_info.nNode-1; // root nodeから while (m_info.node[j].type == NODE_INT) { // 中間ノードの間 if ( GetBit() ) j = m_info.node[j].left; else j = m_info.node[j].right; } // 葉ノードでなければならない if (m_info.node[j].type == NODE_EOD) // 終端ノード break; unsigned char*pData = m_info.node[j].data; switch ( m_info.node[j].type ) { case NODE_LEAF32: *p++ = *pData++; if (p >= pend) break; *p++ = *pData++; if (p >= pend) break; case NODE_LEAF16: *p++ = *pData++; if (p >= pend) break; case NODE_LEAF8: *p++ = *pData++; if (p >= pend) break; break; default: // ありえない break; } } // バッファの残りをzero埋め if (p < pend) memset(p, 0, pend - p); return pend-pDst; } // ブロック番号からオフセットへ変換 size_t CZio::page2Physical(int blk) { unsigned char buf[36]; size_t blkOffs = m_info.epwHdr.idxOffs + ((blk - 1) / 16 * 36); if ( fseek( m_info.fp, blkOffs, SEEK_SET ) != 0 || fread( buf, 1, 36, m_info.fp ) != 36 ) return -1; blkOffs = FOURBYTEUINT(buf) + TWOBYTEUINT(&buf[(blk-1)%16*2+4]); return blkOffs; } ////////////////////////////////////////////////////////////////////////// // S-EBXA ////////////////////////////////////////////////////////////////////////// // S-EBXA書籍の判定 BOOL CZio::check_SEBXA(SEBXAINFO* sinfo) { int bSEBXA = FALSE; unsigned char buf[FRAMESIZE]; unsigned char *p; size_t start,last,blks; size_t lastblk = 0; memset( sinfo,0,sizeof(SEBXAINFO) ); if ( fseek( m_info.fp, 0, SEEK_SET ) != 0 ) return FALSE; if ( fread( buf,1,FRAMESIZE,m_info.fp ) != FRAMESIZE ) return FALSE; int bookitems= TWOBYTEUINT(buf); // 書籍構成要素数 int i; for ( i=0;ichonBlkTop = FOURBYTEUINT(p+2); sinfo->chonBlks = FOURBYTEUINT(p+6); } else if ( p[0] == 0x22 ) { // 圧縮インデックス sinfo->idxBlkTop = FOURBYTEUINT(p+2); sinfo->idxBlks = FOURBYTEUINT(p+6); } else if ( p[0] == 0x00 ) { // 本文 start = sinfo->honBlkTop = FOURBYTEUINT(p+2); blks = sinfo->honBlks = FOURBYTEUINT(p+6); last = start+blks-1; if ( lastblkidxBlks && sinfo->chonBlks ) { bSEBXA = TRUE; m_info.orgSize = lastblk * FRAMESIZE; #if defined(USE_SEBXA_RESIDENT_INDEX) sinfo->idxTbl = (int*)malloc(sinfo->idxBlks*FRAMESIZE+sizeof(int)); // 圧縮インデックス(malloc)0x22の内容のコピー memset(sinfo->idxTbl,0,sinfo->idxBlks*FRAMESIZE); sinfo->nSlice = 0; // スライス数(圧縮インデックスのエントリ数) sinfo->idxTbl[sinfo->nSlice++] = 0; for ( int blkno=sinfo->idxBlkTop; blknoidxBlkTop+sinfo->idxBlks;++blkno ) { if ( fseek( m_info.fp, (blkno-1)*FRAMESIZE, SEEK_SET ) != 0 ) break; for ( int cnt=0;cntidxTbl[sinfo->nSlice++] = FOURBYTEUINT(buf); } } #endif } return bSEBXA; } // S-EBXA 1スライス分(4096バイト長)をデコード int CZio::SEBXA_decode( int srclen, // 伸長前の長さ unsigned char *outbuf, // 出力バッファ int dstlen ) // 出力バッファの長さ { unsigned char buf[1+8*2]; ASSERT( m_info.fp ); unsigned int copy_offs, copy_len; memset( outbuf,0x00,dstlen); int nRead = 0; unsigned char *pDst = outbuf; while ( nRead=0 && copy_offs<(unsigned int)dstlen ); ASSERT(copy_len>0 ); while( copy_len-->0 && (pDst - outbuf)=dstlen ) { start = outbuf; } } } else { // 非圧縮データ if ( fread( buf,1,1,m_info.fp ) != 1 ) break; ++nRead; *pDst++ = buf[0]; } } } // バッファの残りをzero埋め if (pDst < outbuf+SEBXA_SLICE_SIZE) memset(pDst, 0, SEBXA_SLICE_SIZE-(pDst - outbuf) ); ASSERT(pDst-outbuf==dstlen ); return pDst-outbuf; } ////////////////////////////////////////////////////////////////////////// // Util ////////////////////////////////////////////////////////////////////////// // ebzipのCRCチェック // 0 正常時 // -1 チェックサムエラー // -2 EBZip形式ではない int CZio::zCheckCRC() { unsigned char buf[2048]; if ( m_info.type != COMP_EBZIP ) return -2; // EBZipではない unsigned long crc = 1; int blk = 1; int blks = ( m_info.orgSize / 2048 ) + (((m_info.orgSize%2048)>0)?1:0); off_t totalLen = 0; if ( zSeekBlk( 1 ) ) return -1; for ( blk = 1; blk<=blks+1;blk++ ) { if ( zReadBlk( buf ) == 0 ) return -1; int length = min(2048,(off_t)(m_info.orgSize-totalLen) ); totalLen += length; crc = adler32( crc, buf, length ); if ( totalLen >= m_info.orgSize ) { break; } if ( m_callback ) m_callback( m_pParam, blk, blks ); } if ( m_callback ) m_callback( m_pParam, blk, blks ); if ( m_info.CheckSum == crc ) return 0; else return -1; } // zCheckCRC()実行中のUI更新用のコールバック関数の登録 void CZio::SetCallback( void ( *callback )(LPVOID pParam,int current, int total ),LPVOID pData ) { m_callback = callback; m_pParam = pData; } // 情報ブロックを返す ZIO_Info*CZio::zGetInfo() { return &m_info; } // 伸長後のサイズを返す off_t CZio::GetExpandSize() { return m_info.orgSize; } ////////////////////////////////////////////////////////////////////////// // LogoVista ////////////////////////////////////////////////////////////////////////// #if defined(_SSED_SUPPORT) // LogoVista電子辞典のopen // 0:OK -1:ERROR int CZio::SSED_open(FILE *fp) { unsigned char buf[128]; #if defined(_MSC_VER) CFileStatus status; #else struct stat status; #endif TCHAR szFilePath[_MAX_PATH]; if ( fseek( fp, 0, SEEK_SET ) != 0 ) return -1; if ( fread( buf,1, 128, fp ) != 128 ) return -1; m_info.n_element = buf[0x4d]; // 書籍構成要素数 if ( m_info.n_element > 0 ) { m_info.extinfo = (EXT_INFO *)malloc( sizeof(EXT_INFO)*m_info.n_element ); memset( m_info.extinfo,0, sizeof(EXT_INFO)*m_info.n_element ); if ( m_info.extinfo == NULL ) return -1; // 書籍管理情報(書籍の第1ブロックの情報) m_info.ssed_bookinfo = (unsigned char *)malloc(FRAMESIZE); if ( m_info.ssed_bookinfo == NULL ) return -1; memset( m_info.ssed_bookinfo,0,FRAMESIZE ); int nItems = 0; // 書籍管理情報に書く有効な書籍構成要素数 for (int i=0; imulti = buf[2]; pExtInfo->docId = buf[3]; pExtInfo->start = FOURBYTEUINT(buf+4); pExtInfo->end = FOURBYTEUINT(buf+8); pExtInfo->data[0] = buf[12]; pExtInfo->data[1] = buf[13]; pExtInfo->data[2] = buf[14]; pExtInfo->data[3] = buf[15]; strncpy ( (char*)pExtInfo->filename, (char*)&buf[17], 32); pExtInfo->size = pExtInfo->end - pExtInfo->start + 1; pExtInfo->compress = COMP_SSED; // 存在しない書籍構成要素はスキップする _tcscpy( (TCHAR*)szFilePath, (TCHAR*)m_pszFileName ); #if defined(_MSC_VER) _tcscat( (TCHAR*)szFilePath, _T("\\") ); _tcscat( szFilePath, CString(pExtInfo->filename) ); #else _tcscat( (TCHAR*)szFilePath, _T("/") ); _tcscat( (TCHAR*)szFilePath, (TCHAR*)pExtInfo->filename ); #endif #if defined(_MSC_VER) if ( ! CFile::GetStatus( szFilePath, status ) ) { pExtInfo->start = 0; } #else int result = stat( (TCHAR*)szFilePath, &status ); if( result != 0 ) { pExtInfo->start = 0; } #endif if ( m_info.orgSize<(unsigned long)pExtInfo->end*FRAMESIZE ) m_info.orgSize = pExtInfo->end*FRAMESIZE; // start == 0 は外字、または無効要素 if ( pExtInfo->start == 0 ) { continue; } // 複合検索管理情報内の要素は、書籍管理情報には出力しない if ( pExtInfo->multi == 0xFF ) { continue; } /////////////////////////////////// // 以下は書籍管理情報の要素 /////////////////////////////////// // 書籍構成要素識別子 m_info.ssed_bookinfo[16+nItems*16+0] = pExtInfo->docId; // 先頭アドレス unsigned int data = pExtInfo->start; m_info.ssed_bookinfo[16+nItems*16+2] = (data>>24); m_info.ssed_bookinfo[16+nItems*16+3] = ((data>>16)%256); m_info.ssed_bookinfo[16+nItems*16+4] = ((data>>8)%256); m_info.ssed_bookinfo[16+nItems*16+5] = (data%256); // 領域サイズ data = pExtInfo->size; if ( pExtInfo->docId == 0xff ) { // 複合検索管理情報 data = 1; } m_info.ssed_bookinfo[16+nItems*16+6] = (data>>24); m_info.ssed_bookinfo[16+nItems*16+7] = ((data>>16)%256); m_info.ssed_bookinfo[16+nItems*16+8] = ((data>>8)%256); m_info.ssed_bookinfo[16+nItems*16+9] = (data%256); // インデックス作成情報有効性 m_info.ssed_bookinfo[16+nItems*16+10] = pExtInfo->data[0]; m_info.ssed_bookinfo[16+nItems*16+11] = pExtInfo->data[1]; m_info.ssed_bookinfo[16+nItems*16+12] = pExtInfo->data[2]; m_info.ssed_bookinfo[16+nItems*16+13] = pExtInfo->data[3]; ++nItems; } // 書籍構成要素数 m_info.ssed_bookinfo[0] = nItems>>8; m_info.ssed_bookinfo[1] = nItems%256; // 書籍識別 m_info.ssed_bookinfo[2] = 0x00; // インデックス作成情報の取扱法 // 0x00:各書籍構成要素に記録されたインデックス作成情報有効性による // 0x01:インデックス作成情報は意味をもたない // 0x02:インデックス作成情報はすべて有効 m_info.ssed_bookinfo[4] = 0x00; } m_info.ssed_buff = NULL; m_info.ssed_bufflen = 0; return 0; } /* * ヘッダ部 64バイト 00-08: SSEDDATA 09-0e: 不明。バージョン? 0f-0f: 種類? 10-15: 不明 16-17: チャンク数 n_chunk 18-1b: num1 先頭ブロック番号 1c-1f: num2 終了ブロック番号 20-3f: 不明 * オフセット部 n_chunk * 4 バイト オフセットはファイルの先頭からチャンクの開始位置 * チャンク部 5 バイト + n_data * 3 (チャンクヘッダ) 00-01: ゼロ 02-03: データ数 n_data 04-04: ウィンドウの初期化文字 (データ配列) 00-01: オフセット(12bit)と文字数(4bit) 02-02: 文字 ... */ // LogoVista電子辞典の伸長 int CZio::SSED_decode( int blk, EXT_INFO *pInfo, unsigned char *outbuf, // 出力バッファ int bufsize ) // 出力バッファの長さ { TCHAR szFilePath[_MAX_PATH]; unsigned char head[64]; unsigned int chunk_num = 0; // チャンク番号 size_t chunk_offs = 0; // チャンクの開始オフセット size_t chunk_end = 0; // チャンクの開始オフセット int n_data; // チャンク部のデータ数 unsigned char win[0xff0]; // スライド窓 unsigned int wintop = 0; unsigned char *pBuf = outbuf; unsigned char *inBuf; int pos = 0; // outbufへの出力バイト数 if ( m_info.n_element == 0 ) { goto decode_error; } if ( !m_info.extinfo ) { goto decode_error; } if ( !m_info.ssed_buff ) { m_info.ssed_bufflen = SSED_SLICE_SIZE; m_info.ssed_buff = (unsigned char*)malloc( m_info.ssed_bufflen ); } // まだopenしていない場合、open if ( !pInfo->fp ) { // _tcscpy( (TCHAR*)szFilePath, (TCHAR*)m_pszFileName ); #if defined(_MSC_VER) _tcscat( (TCHAR*)szFilePath, _T("\\") ); _tcscat( szFilePath, CString(pInfo->filename) ); #else _tcscat( (TCHAR*)szFilePath, _T("/") ); _tcscat( (TCHAR*)szFilePath, (TCHAR*)pInfo->filename ); #endif #if defined(_MSC_VER) pInfo->fp = _tfopen( (TCHAR*)szFilePath, _T("rb") ); #else pInfo->fp = _tfopen( (TCHAR*)szFilePath, _T("r") ); #endif if ( pInfo->fp == NULL ) goto decode_error; if ( fread( head,1,64,pInfo->fp ) != 64 ) { goto decode_error; } if ( memcmp( head,"SSEDDATA",8 ) != 0 ) { goto decode_error; } pInfo->n_chunk = TWOBYTEUINT( head+22 ); #if defined(USE_SSED_RESIDENT_INDEX) ASSERT( pInfo->n_chunk > 0 ) ; pInfo->idxTbl = (unsigned char*)malloc(4*pInfo->n_chunk); if ( !pInfo->idxTbl ) goto decode_error; if ( fseek( pInfo->fp, 64, SEEK_SET ) != 0 || fread( pInfo->idxTbl,4,pInfo->n_chunk,pInfo->fp ) != pInfo->n_chunk ) { goto decode_error; } #endif } // blkからオフセットを算出 chunk_num = (blk-pInfo->start) / 16; // チャンク番号(0..) ASSERT( chunk_num>= 0 && chunk_numn_chunk ) ; #if defined(USE_SSED_RESIDENT_INDEX) chunk_offs = FOURBYTEUINT( pInfo->idxTbl+chunk_num*4 ); // チャンクの開始オフセット if ( chunk_numn_chunk-1 ) { chunk_end = FOURBYTEUINT( pInfo->idxTbl+chunk_num*4+4 ); // チャンクの終了オフセット } else { if ( fseek( pInfo->fp, 0, SEEK_END ) != 0 || (chunk_end = ftell( pInfo->fp ) ) == -1L ) { goto decode_error; } } #else size_t offset; unsigned char buff[4]; offset = chunk_num*4+64; if ( fseek( pInfo->fp, offset, SEEK_SET ) != 0 || fread( buff,1,4,pInfo->fp ) != 4 ) { goto decode_error; } chunk_offs = FOURBYTEUINT(buff); // チャンクの開始オフセット if ( chunk_numn_chunk-1 ) { if ( fread( buff,1,4,pInfo->fp ) != 4 ) { goto decode_error; } chunk_end = FOURBYTEUINT( buff ); // チャンクの終了オフセット } else { if ( fseek( pInfo->fp, 0, SEEK_END ) != 0 || (chunk_end = ftello( pInfo->fp ) ) == -1L ) { goto decode_error; } } #endif ASSERT( chunk_offs=chunk_end ) { goto decode_error; } if ( chunk_end-chunk_offs>(size_t)m_info.ssed_bufflen ) { ASSERT( chunk_end-chunk_offs<=SSED_SLICE_SIZE*2 ); if ( chunk_end-chunk_offs>SSED_SLICE_SIZE*2 ) { goto decode_error; } m_info.ssed_bufflen = (chunk_end-chunk_offs+FRAMESIZE)/FRAMESIZE*FRAMESIZE; m_info.ssed_bufflen += (m_info.ssed_bufflen % FRAMESIZE); m_info.ssed_buff = (unsigned char*)realloc( m_info.ssed_buff, m_info.ssed_bufflen ); if ( !m_info.ssed_buff ) goto decode_error; } // チャンクを読む if ( fseek( pInfo->fp, chunk_offs, SEEK_SET ) != 0 || fread( m_info.ssed_buff,1,chunk_end-chunk_offs,pInfo->fp ) != chunk_end-chunk_offs ) { goto decode_error; } inBuf = m_info.ssed_buff; n_data = TWOBYTEUINT(inBuf+2); // チャンクに含まれるデータ数 // チャンク部のデータ配列を展開する memset (win, inBuf[4], sizeof win); // スライド窓の初期化 inBuf += 5; int d; for (d=0; d> 4); len = inBuf[1] & 0x0f; for (j=0; j= bufsize // 出力バッファが埋まった || d == n_data-1 && !(pos & 0x7ff)) // 最終データは2048バイトで打ち切る break; w = wp + wintop; if (w >= sizeof win) w -= sizeof win; win[wintop++] = win[w]; if (wintop >= sizeof win) wintop = 0; *pBuf++ = win[w]; pos ++; } if (pos >= bufsize // 出力バッファが埋まった || d == n_data-1 && !(pos & 0x7ff)) // 最終データは2048バイトで打ち切る break; win[wintop++] = inBuf[2]; if (wintop >= sizeof win) wintop = 0; *pBuf++ = inBuf[2]; pos ++; inBuf += 3; } return bufsize; decode_error: return 0; } #endif