📄 tcsylist.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
// TcsyList.cpp 扇区内注册管理双向链表类声明及实现,标准C++版本
// CopyRight(C) 1996,2008 TCSY 公司
// Pentium Working Room ShanChengKun 2004.05.27 更新
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "HDiskSN.h"
#include "TcsyList.h"
#include "Resource.h"
/////////////////////////////////////////////////////////////////////////////
// CSearchBin类相关函数实现定义:
// 二进制查找类:默认构造函数
CSearchBin::CSearchBin()
{
memset(m_BinEntry, 0, sizeof(m_BinEntry));
m_byPattern = NULL; m_nLenPatt = 0L;
}
// 二进制查找类:自定义构造函数
CSearchBin::CSearchBin(const BYTE *byPattern, long nLenPatt, long nStyle)
{
SetBinEntry(byPattern, nLenPatt, nStyle);
}
// 修正应用通配符情况下的模板串:除去两端的通配符
void CSearchBin::ReviseTokenPatt(BYTE *&pDes, long &nDesLen,
long nStyle, BYTE byToken)
{
if((nStyle & 0x04) == 0) return; // 是否使用通配符
BYTE *pCurr = pDes; // 处理二进制串首
while(pCurr < pDes + nDesLen) {if(*pCurr != byToken) break; pCurr++;}
nDesLen -= (pCurr - pDes); pDes = pCurr; // 修正指针及长度
pCurr = pDes + nDesLen - 1; // 处理二进制串尾
while(pCurr >= pDes) {if(*pCurr != byToken) break; pCurr--;}
nDesLen = pCurr - pDes + 1; // 修正二进制串长
}
// 设置匹配模板,并初始化256级位置入口记录
void CSearchBin::SetBinEntry(const BYTE *byPattern, long nLenPatt, long nStyle)
{
m_byPattern = byPattern;
m_nLenPatt = nLenPatt;
m_nSearchStyle = nStyle;
bool bCapCase = (bool)((nStyle & 0x02) != 0);
long k = 0; BYTE byNth = 0;
for(k=0; k<256; k++) m_BinEntry[k] = m_nLenPatt + 1;
for(k=0; k<m_nLenPatt; k++)
{
if(bCapCase) byNth = m_byPattern[k];
else byNth = ToUpper(m_byPattern[k]);
m_BinEntry[byNth] = m_nLenPatt - k;
}
}
//-------------------------------------------------------------------------//
// 查找匹配二进制串算法主体(改进BMH),并目标计数、或返回位置(零起始)
long CSearchBin::FindBin(const BYTE *byStream, long nLength)
{
if(m_nLenPatt > nLength) return (-1); // 长度安检
long nStyle = m_nSearchStyle, nCount = 0; // 查找类型
long k = m_nLenPatt - 1, i = 0, j = 0;
bool bGainPos = (bool)((nStyle & 0x01) != 0); // 返回首位
while(k < nLength)
{
j = m_nLenPatt - 1; // 尾部开始
i = k;
while(j >= 0 && m_byPattern[j] == byStream[i])
{
j--; i--; // 前一字符
}
if(j < 0) // 找到目标
{
if(bGainPos) return (i + 1); // 串首位置
else {nCount++; k++;} // 目标计数
}
else k += m_BinEntry[byStream[k + 1]]; // 移动模板
}
return (!bGainPos ? nCount : -1); // 返回结果
}
// 查找匹配二进制串算法主体(改进BMH),并目标计数、或返回位置(零起始)
long CSearchBin::FindBinEx(const BYTE *byStream, long nLength, BYTE byToken)
{
if(m_nLenPatt > nLength) return (-1); // 长度的安检
long nStyle = m_nSearchStyle, nCount = 0; // 查找的方式
long k = m_nLenPatt - 1, i = 0, j = 0;
long nOffPos = 0; BYTE byNth = 0; // 位移和入口
bool bGainPos = (bool)((nStyle & 0x01) != 0); // 返回首位置
bool bCapCase = (bool)((nStyle & 0x02) != 0); // 大小写敏感
bool bTokenIt = (bool)((nStyle & 0x04) != 0); // 是否用通配
while(k < nLength)
{
j = m_nLenPatt - 1; // 尾部开始
i = k;
while(j >= 0 && (byStream[i] == m_byPattern[j] ||
(bTokenIt && ToUpper(m_byPattern[j]) == byToken) ||
(!bCapCase && ToUpper(byStream[i]) == ToUpper(m_byPattern[j]))))
{
j--; i--; // 前一字符
}
if(j < 0) // 找到目标
{
if(bGainPos) return (i + 1); // 串首位置
else {nCount++; k++;} // 目标计数
}
else // 模板不匹
{
if(bCapCase) byNth = byStream[k + 1]; // 计数入口
else byNth = ToUpper(byStream[k + 1]);
nOffPos = m_BinEntry[byNth]; // 修正位移
if(bTokenIt && nOffPos > m_BinEntry[byToken])
nOffPos = m_BinEntry[byToken]; // 取小的量
k += nOffPos; // 移动模板
}
}
return (!bGainPos ? nCount : -1); // 返回结果
}
// 在给定的二进制区域中搜索指定长度的连续空域,并返回首位置
BYTE *CSearchBin::SearchEmptyArea(BYTE bySrc[], long nSrcLen,
long nEmptyLen, BYTE byEmpty)
{
BYTE *pFirstOccur = NULL; // 首次出现
long i = 0, nAreaSize = 0, nEndPosit = nSrcLen - nEmptyLen - 1;
for(i=0; i<nSrcLen; i++) // 遍历区域
{
if(bySrc[i] == byEmpty) // 发现空闲
{
if(pFirstOccur) {if(++nAreaSize >= nEmptyLen) break;}
else {pFirstOccur = &bySrc[i]; nAreaSize = 1;}
}
else if(pFirstOccur) {pFirstOccur = NULL; nAreaSize = 0;}
if(nEndPosit + nAreaSize < i) {pFirstOccur = NULL; break;}
}
return pFirstOccur; // 返回指针
}
/////////////////////////////////////////////////////////////////////////////
// CTcsyRegistList类相关函数实现定义:
// 在New申请的空间中,首尾要写入相关的记录数据,用于确认写单元
VOID CTcsyRegistList::WriteNewFlag(BYTE *pStart, WORD wDataSize)
{
if(pStart == NULL || wDataSize < 1) return; // 检查入口数据
BYTE *pOccur = pStart - NEW_RECSIZE - EXTEND_BYTES;
memset(pOccur, BYTE_EMPTY, EXTEND_BYTES); // 清空首延拓值
*(pOccur + EXTEND_BYTES) = EXTEND_BYTES; // 记录延拓大小
*((WORD *)(pStart - sizeof(WORD))) = wDataSize; // 实际数据大小
memset(pStart + wDataSize, BYTE_EMPTY, EXTEND_BYTES);// 尾部延拓
}
// 校验Znn文件是否正确:文件路径及名称需先生成
BOOL CTcsyRegistList::IsCorrectZnnFile(const char *chFile)
{
HANDLE hFile = CreateFile(chFile, GENERIC_READ, FILE_SHARE_READ |
FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL);
SFileRegistHead sHead; // 临时文件标头
DWORD dwReturn = 0L; // 返回读取大小
BOOL bCorrect = FALSE; // 标头是否正确
if(hFile != INVALID_HANDLE_VALUE && // 开始读取数据
GetFileSize(hFile, NULL) == (DWORD)ZNN_FILE_SIZE &&
ReadFile(hFile, &sHead, sizeof(sHead), &dwReturn, NULL) &&
dwReturn == sizeof(sHead)) // 大小都已正确
{
bCorrect = sHead.DecodeHead(); // 解包是否成功
}
if(hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile);
return bCorrect; // 返回是否正确
}
// 检查Znn映象文件中的标头数据中是否标记已更新过
BOOL CTcsyRegistList::IsZnnFileUpdate(VOID)
{
BYTE *pBase = m_ZnnFile.GetMapPtr(); // 获取映象基址
if(pBase == NULL) return FALSE; // 文件尚未映象
SFileRegistHead sHead; // 临时文件标头
memcpy(&sHead, pBase, sizeof(sHead)); // 读取出源数据
if(!sHead.DecodeHead()) return FALSE; // 解包校验失败
return sHead.bUpdateRecent; // 返回是否更新
}
// 将更新的情况写入Znn文件映象中的标头
BOOL CTcsyRegistList::SaveZnnFileHead(BOOL bUpdate)
{
BYTE *pBase = m_ZnnFile.GetMapPtr(); // 获取映象基址
if(pBase == NULL) return FALSE; // 文件尚未映象
SFileRegistHead sHead; // 临时文件标头
memcpy(&sHead, pBase, sizeof(sHead)); // 读取出源数据
if(!sHead.DecodeHead()) return FALSE; // 解包校验失败
if(!sHead.EncodeHead(bUpdate)) return FALSE; // 返回打包结果
memcpy(pBase, &sHead, sizeof(sHead)); // 将数据写入扇
return TRUE; // 成功更新数据
}
//-------------------------------------------------------------------------//
// 从当前指针开始是否有nLen长度的连续的byData
BOOL CTcsyRegistList::IsKeepAs(BYTE *pCurr, LONG nLen, BYTE byData)
{
while((--nLen) >= 0) // 全长搜索目标
{if(pCurr[nLen] != byData) return FALSE;}
return TRUE; // 含有指定长度
}
// 所给的地址是否有效,在合法的范围内
inline BOOL CTcsyRegistList::IsValidAddr(const STcsyRegistAddr &sAddr)
{
return (sAddr.dwSectNum >= MIN_SECT_NUM && sAddr.dwSectNum <= MAX_SECT_NUM
&& sAddr.nByteOffs >= 0 && sAddr.nByteOffs < DISK_SECTOR_SIZE);
}
// 判断给定的两个地址是否相同
inline BOOL CTcsyRegistList::IsSameAddr(const STcsyRegistAddr &sAddr,
const STcsyRegistAddr &dAddr)
{
return ((sAddr.dwSectNum == dAddr.dwSectNum) &&
(sAddr.nByteOffs == dAddr.nByteOffs));
}
// 测试读写扇区的功能是否可以使用:先读出来再写回去
inline BOOL CTcsyRegistList::IsEnableDiskIO(VOID)
{
BYTE byBuff[DISK_SECTOR_SIZE] = {0}; // 扇区临时缓冲
BOOL bEnable = (BOOL)DiskSectorIO(USE_WHICH_DISK, USE_DISK_NUM,
MAX_SECT_NUM, 1, (LONG)byBuff, READ_SECT);
if(bEnable) bEnable = (BOOL)DiskSectorIO(USE_WHICH_DISK, USE_DISK_NUM,
MAX_SECT_NUM, 1, (LONG)byBuff, WRITE_SECT);
return bEnable; // 读取磁盘扇区
}
// 释放磁盘上扇区空间:方便自己测试专用的
BOOL CTcsyRegistList::DirectRemove(DWORD dwNumb, LONG nOffs)
{
STcsyRegistAddr sAddr; // 转换成本地址
sAddr.dwSectNum = dwNumb;
sAddr.nByteOffs = nOffs;
return Delete(sAddr); // 直接删除目标
}
//-------------------------------------------------------------------------//
// 获取磁盘注册单元的数,因断链有处理,故若>=0则与映象节点总数相同
LONG CTcsyRegistList::GetItemCount()
{
return TcsyHead.nItemCount;
}
// 获取注册数据的标头,以提供所占用扇区的信息
VOID CTcsyRegistList::GetTcsyHead(STcsyRegistHead *pHead)
{
if(pHead) *pHead = TcsyHead;
}
// 移动当前指针到:假=首节点、真=尾节点
VOID CTcsyRegistList::ToRewind(BOOL bEndOrNot)
{
PtrCurr = bEndOrNot ? PtrEnd : PtrStart;
}
// 移动当前指针到上一节点
BOOL CTcsyRegistList::ToPrior(VOID)
{
if(!PtrCurr || !PtrCurr->PtrPrior) return FALSE;
PtrCurr = PtrCurr->PtrPrior; return TRUE;
}
// 移动当前指针到下一节点
BOOL CTcsyRegistList::ToNext(VOID)
{
if(!PtrCurr || !PtrCurr->PtrNext) return FALSE;
PtrCurr = PtrCurr->PtrNext; return TRUE;
}
// 读当前节的内存数据拷贝,与磁盘对应的相同:要先解密
BOOL CTcsyRegistList::ReadCurr(STcsyRegistData *pData)
{
if(!PtrCurr || !pData) return FALSE; // 当前指针无效
*pData = PtrCurr->ItemData.RegData;
CryptXOR((BYTE *)pData, sizeof(STcsyRegistData));
return TRUE; // 返回当前拷贝
}
// 更新当前节到内存,并保存磁盘的对应扇区:要再加密
BOOL CTcsyRegistList::WriteCurr(const STcsyRegistData *pData)
{
if(!PtrCurr || !pData) return FALSE; // 当前指针无效
STcsyRegistData &rData = PtrCurr->ItemData.RegData;
PtrCurr->ItemData.RegData = *pData;
CryptXOR((BYTE *)(&rData), sizeof(STcsyRegistData));
return SaveDiskItem(PtrCurr->ItemData); // 存到磁盘扇区
}
// 文件底层模拟扇区操作:功能和位置相当于DiskSectorIO(...)函数
inline BOOL CTcsyRegistList::FileSectorIO(BYTE *pSector,
DWORD dwStart,
LONG bOpera)
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -