#pragma once
|
/*
|
* HashTable File
|
* Version 1.22 2019-02-25
|
* Description:
|
*
|
*
|
*/
|
|
#include <string>
|
#include <iostream>
|
#include <fstream>
|
#include "../Utils.h"
|
|
inline std::string trim(const std::string& s)
|
{
|
char p[] = " \t\r\n";
|
long sp = 0;
|
long ep = (long)s.length() - 1;
|
for (; sp <= ep; ++sp)
|
if (!strchr(p, s[sp])) break;
|
for (; ep >= 0; --ep)
|
if (!strchr(p, s[ep])) break;
|
return s.substr(sp, ep-sp+1);
|
}
|
//struct stCfgCtrl //ÅäÖÃÎļþÏîºÍ¿Ø¼þ¶ÔÓ¦¹Øϵ
|
//{
|
// CStringA sKeyName;
|
// UINT nCtrlId;
|
//};
|
enum enVtype //±äÁ¿ÀàÐÍ
|
{
|
vtNone = 0,
|
vtbool =1,
|
vtInt = 2,
|
vtFloat = 3,
|
vtDouble = 4,
|
vtString = 5,
|
};
|
enum enCType //¿Ø¼þÀàÐÍ
|
{
|
ctNone =0,
|
ctStatic=1,
|
ctEdit=2,
|
ctCheckBox=3,
|
ctRadio=4,
|
ctComboBoxIndex=5, //ComboBox Index;
|
ctComboBoxString = 6, // ComboBox String;
|
ctListBox = 6,
|
ctListCtrl=7,
|
};
|
struct stCfgValCtrl //ÅäÖÃÎļþÏîºÍ±äÁ¿ÒÔ¼°¿Ø¼þ¶ÔÓ¦¹Øϵ
|
{
|
CStringA sKeyName;
|
int vType;
|
void * var;
|
UINT nCtrlId;
|
int cType;
|
};
|
template <typename T, size_t N>
|
char(&_ArraySizeHelper(T(&array)[N]))[N];
|
#define countof(array) (sizeof(_ArraySizeHelper(array)))
|
|
#define MAX_HASH_KEY 3000
|
#define MAX_MHASH_SEGMENT 300
|
class Hashelement
|
{
|
public:
|
int HashValue;
|
CString * Key;
|
CString * Value;
|
Hashelement()
|
{
|
HashValue = 0;
|
Key = NULL;
|
Value = NULL;
|
}
|
~Hashelement()
|
{
|
delete Key;
|
delete Value;
|
Key = NULL;
|
Value = NULL;
|
}
|
Hashelement(const Hashelement& elem)
|
{
|
*this = elem;
|
}
|
Hashelement& operator = (const Hashelement& elem)
|
{
|
if (this == &elem)
|
{
|
return *this;
|
}
|
HashValue = elem.HashValue;
|
|
delete Key;
|
delete Value;
|
Key = new CString(*(elem.Key));
|
Value = new CString(*(elem.Value));
|
|
return *this;
|
}
|
operator int ()
|
{
|
return _tstoi(*Value);
|
}
|
operator float()
|
{
|
return float(_tstof(*Value));
|
}
|
operator double()
|
{
|
return _tstof(*Value);
|
}
|
operator LPCTSTR()
|
{
|
return *Value;
|
}
|
//operator CString()
|
//{
|
// return *Value;
|
//}
|
|
//operator TCHAR *()
|
//{
|
// return *Value;
|
//}
|
int operator =(int i)
|
{
|
if (Value == nullptr) { Value = new CString; }
|
(*Value).Format(_T("%d"),i);
|
return i;
|
}
|
float operator =(float f)
|
{
|
if (Value == nullptr) { Value = new CString; }
|
(*Value).Format(_T("%f"), f);
|
return f;
|
}
|
double operator =(double d)
|
{
|
if (Value == nullptr) { Value = new CString; }
|
(*Value).Format(_T("%f"), d);
|
return d;
|
}
|
CString operator =(CString s)
|
{
|
if (Value == nullptr) { Value = new CString; }
|
*Value = s;
|
return s;
|
}
|
|
};
|
|
class Hash
|
{
|
public:
|
|
CString Name;
|
int TotalKey;
|
Hashelement elements[MAX_HASH_KEY];
|
|
Hashelement OverFlow;
|
public:
|
|
~Hash()
|
{
|
}
|
|
Hash(void)
|
{
|
TotalKey=0;
|
OverFlow = _T("OverFlow");
|
};
|
Hash(CString thisName)
|
{
|
TotalKey=0;
|
this->Name=thisName;
|
OverFlow = _T("OverFlow");
|
};
|
Hash(const Hash& hash)
|
{
|
*this = hash;
|
OverFlow = _T("OverFlow");
|
}
|
|
Hash& operator = (const Hash& hash)
|
{
|
if (this == &hash)
|
{
|
return *this;
|
}
|
Name = hash.Name;
|
TotalKey = hash.TotalKey;
|
for (int i=0; i<TotalKey; ++i)
|
{
|
elements[i] = hash.elements[i];
|
}
|
return *this;
|
}
|
void Empty(void)
|
{
|
int i;
|
for (i=0;i<this->TotalKey;i++)
|
{
|
delete elements[i].Key;
|
delete elements[i].Value;
|
}
|
TotalKey=0;
|
}
|
bool Exist(CString s)
|
{
|
int left = 0;
|
int right = TotalKey - 1;
|
int mid;
|
|
int index = -1;
|
while (left <= right)
|
{
|
mid = (left + right) / 2;
|
int r = elements[mid].Key->CompareNoCase(s);
|
if (r < 0)
|
{//keyÔÚÓÒ±ß
|
left = mid + 1;
|
}
|
else if (r > 0)
|
{//keyÔÚ×ó±ß
|
right = mid - 1;
|
}
|
else
|
{
|
index = mid;
|
break;
|
}
|
}
|
if (index == -1) return false;
|
else return true;
|
}
|
Hashelement & operator [] (const char * str)
|
{
|
CString s1(str);
|
return this->operator [] (s1);
|
};
|
Hashelement & operator [] (CString s)
|
{
|
int left = 0;
|
int right = TotalKey - 1;
|
int mid;
|
|
int index = -1;
|
while (left <= right)
|
{
|
mid = (left + right) / 2;
|
int r = elements[mid].Key->CompareNoCase(s);
|
if (r < 0)
|
{//keyÔÚÓÒ±ß
|
left = mid + 1;
|
} else if (r > 0)
|
{//keyÔÚ×ó±ß
|
right = mid - 1;
|
} else
|
{
|
index = mid;
|
break;
|
}
|
}
|
|
if (index == -1 && TotalKey < MAX_HASH_KEY)
|
{
|
index = left;
|
for (int i = TotalKey; i > index; --i)
|
{
|
elements[i].Key = elements[i-1].Key;
|
elements[i].Value = elements[i-1].Value;
|
}
|
|
elements[index].Key = new CString(s);
|
elements[index].Value = new CString(s);
|
TotalKey++;
|
}
|
|
if (index==-1)
|
{
|
return OverFlow;
|
}
|
|
return elements[index];
|
};
|
Hashelement & operator [] (int k)
|
{
|
return elements[k];
|
};
|
|
template <typename T, size_t N>
|
int inline SetVarList(T(&pCfgs)[N])
|
{
|
return SetVarList(pCfgs, N);
|
}
|
|
int SetVarList(stCfgValCtrl *pCfgs, int nCount)
|
{
|
for (int i = 0; i < nCount; i++)
|
{
|
int vtype = pCfgs[i].vType;
|
void * pvar = pCfgs[i].var;
|
int nCtrlId = pCfgs[i].nCtrlId;
|
if (pvar==nullptr) continue;
|
|
switch (vtype)
|
{
|
case vtbool:
|
case vtInt: *(int *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
|
case vtFloat:*(float *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
|
case vtDouble:*(double *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
|
case vtString:*(CString *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
|
default:
|
break;
|
}
|
}
|
return nCount;
|
}
|
int SetCtrl(const char * str, CWnd * pWnd, int nCtrlId, int nCtrlType)
|
{
|
CString s1(str);
|
return SetCtrl(s1, pWnd, nCtrlId,nCtrlType);
|
}
|
int SetCtrl(CString str, CWnd * pWnd, int nCtrlId, int nCtrlType)
|
{
|
if (nCtrlId == 0) return 0;
|
CWnd * pCtrl = pWnd->GetDlgItem(nCtrlId);
|
if (pCtrl == nullptr) return -1;
|
switch (nCtrlType)
|
{
|
case ctEdit:
|
pWnd->SetDlgItemText(nCtrlId, this->operator [] (str)); break;
|
case ctCheckBox:
|
((CButton *)pCtrl)->SetCheck(this->operator [] (str)); break;
|
case ctComboBoxIndex:
|
((CComboBox*)pCtrl)->SetCurSel(this->operator [] (str)); break;
|
case ctComboBoxString:
|
((CComboBox*)pCtrl)->SelectString(0,this->operator [] (str));
|
pWnd->SetDlgItemText(nCtrlId, this->operator [] (str)); break;
|
default:
|
break;
|
}
|
return 0;
|
}
|
|
template <typename T,size_t N>
|
int inline SetCtrlList(CWnd * pWnd, T (&pCfgs)[N])
|
{
|
return SetCtrlList(pWnd, pCfgs, N);
|
}
|
|
int SetCtrlList(CWnd * pWnd, stCfgValCtrl * pCfgs, int nCount)
|
{
|
for (int i = 0; i < nCount; i++)
|
{
|
|
int vtype = pCfgs[i].vType;
|
void * pvar = pCfgs[i].var;
|
int nCtrlId = pCfgs[i].nCtrlId;
|
int nCtrlType = pCfgs[i].cType;
|
SetCtrl(pCfgs[i].sKeyName, pWnd, nCtrlId,nCtrlType);
|
|
if (pvar == nullptr) continue;
|
switch (vtype)
|
{
|
case vtbool:
|
case vtInt: *(int *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
|
case vtFloat:*(float *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
|
case vtDouble:*(double *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
|
case vtString:*(CString *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
|
default:
|
break;
|
}
|
|
}
|
return nCount;
|
}
|
template <typename T, size_t N>
|
int inline GetCtrlList(CWnd * pWnd, T(&pCfgs)[N])
|
{
|
return GetCtrlList(pWnd, pCfgs, N);
|
}
|
|
int GetCtrl(const char * str, CWnd * pWnd, int nCtrlId, int nCtrlType)
|
{
|
CString s1(str);
|
return GetCtrl(s1, pWnd, nCtrlId, nCtrlType);
|
}
|
int GetCtrl(CString str, CWnd * pWnd, int nCtrlId, int nCtrlType)
|
{
|
if (nCtrlId == 0) return 0;
|
CString s1;
|
CWnd * pCtrl = pWnd->GetDlgItem(nCtrlId);
|
if (pCtrl == nullptr) return -1;
|
|
switch (nCtrlType)
|
{
|
case ctEdit:
|
pWnd->GetDlgItemText(nCtrlId, s1); this->operator [] (str) = s1; break;
|
case ctCheckBox:
|
this->operator [] (str) = ((CButton *)pCtrl)->GetCheck(); break;
|
case ctComboBoxIndex:
|
this->operator [] (str)=((CComboBox *)pCtrl)->GetCurSel(); break;
|
case ctComboBoxString:
|
pWnd->GetDlgItemText(nCtrlId, s1); this->operator [] (str) = s1; break;
|
|
default:
|
break;
|
}
|
return 0;
|
}
|
|
int GetCtrlList(CWnd * pWnd, stCfgValCtrl * pCfgs, int nCount)
|
{
|
for (int i = 0; i < nCount; i++)
|
{
|
int vtype = pCfgs[i].vType;
|
void * pvar = pCfgs[i].var;
|
int nCtrlId = pCfgs[i].nCtrlId;
|
int nCtrlType = pCfgs[i].cType;
|
GetCtrl(pCfgs[i].sKeyName, pWnd, nCtrlId,nCtrlType);
|
|
if (pvar == nullptr) continue;
|
switch (vtype)
|
{
|
case vtbool:
|
case vtInt: *(int *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
|
case vtFloat:*(float *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
|
case vtDouble:*(double *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
|
case vtString:*(CString *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
|
default:
|
break;
|
}
|
|
}
|
return nCount;
|
}
|
int SaveToFile(CString FilePathName,CString Section)
|
{
|
int i;
|
CString Key,Value;
|
CString CurrentDirectory;
|
|
for (i=0;i<TotalKey;i++)
|
{
|
Key=*(elements[i].Key);
|
Value=*(elements[i].Value);
|
Value.Replace(_T("\r\n"),_T("<CR><LF>"));
|
Value.Replace(_T("\r"),_T("<CR>"));
|
Value.Replace(_T("\n"),_T("<LF>"));
|
WritePrivateProfileString(Section,Key,Value,FilePathName);
|
}
|
return 1;
|
};
|
|
int LoadFromFile(CString FilePathName,CString Section)
|
{
|
CString Key;
|
CString value,value1,value2;
|
CString Defaultstr;
|
Defaultstr=_T("");
|
int k,l;
|
CString s1,s2,s3;
|
k=GetPrivateProfileString(NULL,NULL,Defaultstr,value1.GetBuffer(40960),40960,FilePathName);
|
value1.ReleaseBuffer(k);
|
TCHAR * p2;
|
int n1,n2,n3;
|
n3=GetPrivateProfileString(Section,NULL,Defaultstr,value2.GetBuffer(40960),40960,FilePathName);
|
for (n1=0;n1<n3;n1++)
|
{
|
p2=s3.GetBuffer(40960);
|
for (n2=0;;n2++)
|
{
|
if (value2.GetString()[n1+n2])
|
{p2[n2]=(value2.GetString())[n1+n2];}
|
else
|
{break;}
|
}
|
s3.ReleaseBuffer(n2);
|
|
Key=s3;
|
|
l=GetPrivateProfileString(Section,Key,Defaultstr,value.GetBuffer(40960),40960,FilePathName);
|
value.ReleaseBuffer();
|
value.Replace(_T("<CR><LF>"),_T("\r\n"));
|
value.Replace(_T("<CR>"),_T("\r"));
|
value.Replace(_T("<LF>"),_T("\n"));
|
this->operator [](Key)=value;
|
n1+=n2;
|
}
|
return 1;
|
};
|
};
|
|
class MHashelement
|
{
|
public:
|
int HashValue;
|
CString SegmentName;
|
Hash * Segment;
|
|
MHashelement()
|
{
|
HashValue = 0;
|
SegmentName = _T("");
|
Segment = NULL;
|
}
|
|
~MHashelement()
|
{
|
delete Segment;
|
Segment = NULL;
|
}
|
|
MHashelement(const MHashelement& elem)
|
{
|
*this = elem;
|
}
|
MHashelement& operator = (const MHashelement& elem)
|
{
|
if (this == &elem)
|
{
|
return *this;
|
}
|
HashValue = elem.HashValue;
|
SegmentName = elem.SegmentName;
|
|
delete Segment;
|
Segment = new Hash(*(elem.Segment));
|
|
return *this;
|
};
|
};
|
class MHash
|
{
|
public:
|
int TotalSegment;
|
MHashelement elements[MAX_MHASH_SEGMENT];
|
|
Hash OverFlow;
|
~MHash()
|
{
|
};
|
|
MHash(void)
|
{
|
TotalSegment=0;
|
OverFlow = Hash(_T("OverFlow"));
|
};
|
|
MHash(const MHash& mhash)
|
{
|
*this = mhash;
|
OverFlow = Hash(_T("OverFlow"));
|
}
|
|
MHash& operator = (const MHash& mhash)
|
{
|
if (this == &mhash)
|
{
|
return *this;
|
}
|
TotalSegment=mhash.TotalSegment;
|
for (int i=0;i<TotalSegment;i++)
|
{
|
elements[i] = mhash.elements[i];
|
}
|
return *this;
|
}
|
void Empty()
|
{
|
int i;
|
for (i=0;i<TotalSegment;i++)
|
{
|
delete elements[i].Segment;
|
}
|
TotalSegment=0;
|
}
|
Hash & operator [] (const char * str)
|
{
|
CString s1(str);
|
return this->operator [] (s1);
|
};
|
|
Hash & operator [] (CString s)
|
{
|
int left = 0;
|
int right = TotalSegment - 1;
|
int mid;
|
|
int index = -1;
|
while (left <= right)
|
{
|
mid = (left + right) / 2;
|
int r = elements[mid].SegmentName.CompareNoCase(s);
|
if (r < 0)
|
{//keyÔÚÓÒ±ß
|
left = mid + 1;
|
} else if (r > 0)
|
{//keyÔÚ×ó±ß
|
right = mid - 1;
|
} else
|
{
|
index = mid;
|
break;
|
}
|
}
|
|
if (index == -1 && TotalSegment < MAX_MHASH_SEGMENT)
|
{
|
index = left;
|
for (int i = TotalSegment; i > index; --i)
|
{
|
elements[i].Segment = elements[i-1].Segment;
|
elements[i].SegmentName = elements[i-1].SegmentName;
|
}
|
elements[index].Segment= new Hash(s);
|
elements[index].SegmentName = s;
|
TotalSegment++;
|
}
|
|
if (index==-1)
|
{
|
return OverFlow;
|
}
|
|
return *(elements[index].Segment);
|
};
|
Hash & operator [] (int k)
|
{
|
return *(elements[k].Segment);
|
};
|
|
int SaveToFileOld(CString FilePathName)
|
{
|
int i,j;
|
CString Section;
|
CString Key,Value;
|
CString CurrentDirectory;
|
|
for (i=0;i<TotalSegment;i++)
|
{
|
Section=elements[i].SegmentName;
|
for (j=0;j<this->operator [](i).TotalKey;j++)
|
{
|
Key=*(this->operator [](i).elements[j].Key) ;
|
Value=*(this->operator [](i).elements[j].Value);
|
Value.Replace(_T("\r\n"),_T("<CR><LF>"));
|
Value.Replace(_T("\r"),_T("<CR>"));
|
Value.Replace(_T("\n"),_T("<LF>"));
|
WritePrivateProfileString(Section,Key,Value,FilePathName);
|
}
|
}
|
return 1;
|
};
|
|
int LoadFromFileOld(CString FilePathName)
|
{
|
CString Key;
|
CString Value,value1,value2;
|
CString Section;
|
CString Defaultstr;
|
Defaultstr=_T("");
|
this->Empty();
|
int i,j,k,l;
|
CString s1,s2,s3;
|
k=GetPrivateProfileString(NULL,NULL,Defaultstr,value1.GetBuffer(40960),40960,FilePathName);
|
value1.ReleaseBuffer(k);
|
TCHAR * p1;
|
TCHAR * p2;
|
int n1,n2,n3;
|
for (i=0;i<k;i++)
|
{
|
p1=s2.GetBuffer(40960);
|
for (j=0;;j++)
|
{
|
if ((value1.GetString())[i+j])
|
{p1[j]=((LPTSTR)value1.GetString())[i+j];}
|
else
|
{ break;}
|
}
|
s2.ReleaseBuffer(j);
|
Section=s2;
|
n3=GetPrivateProfileString(Section,NULL,Defaultstr,value2.GetBuffer(40960),40960,FilePathName);
|
|
for (n1=0;n1<n3;n1++)
|
{
|
p2=s3.GetBuffer(40960);
|
for (n2=0;;n2++)
|
{
|
if (value2.GetString()[n1+n2])
|
{p2[n2]=(value2.GetString())[n1+n2];}
|
else
|
{break;}
|
}
|
s3.ReleaseBuffer(n2);
|
|
Key=s3;
|
|
l=GetPrivateProfileString(Section,Key,Defaultstr,Value.GetBuffer(40960),40960,FilePathName);
|
Value.ReleaseBuffer();
|
Value.Replace(_T("<CR><LF>"),_T("\r\n"));
|
Value.Replace(_T("<CR>"),_T("\r"));
|
Value.Replace(_T("<LF>"),_T("\n"));
|
this->operator [](Section)[Key]=Value;
|
n1+=n2;
|
}
|
|
i+=j;
|
}
|
|
return k;
|
};
|
|
int SaveToFile(CString FilePathName)
|
{
|
std::string filename = CString2String(FilePathName);
|
std::ofstream ofs(filename);
|
if (!ofs.is_open())
|
{
|
std::cerr << "Save MHash error, open file" << filename << " fail." << std::endl;
|
return -1;
|
}
|
|
int i,j;
|
CString Section;
|
CString Key,Value;
|
|
for (i=0;i<TotalSegment;i++)
|
{
|
Section=elements[i].SegmentName;
|
ofs << "[" << CString2String(Section) << "]" << std::endl;
|
|
for (j=0;j<this->operator [](i).TotalKey;j++)
|
{
|
Key=*(this->operator [](i).elements[j].Key) ;
|
Value=*(this->operator [](i).elements[j].Value);
|
Value.Replace(_T("\r\n"),_T("<CR><LF>"));
|
Value.Replace(_T("\r"),_T("<CR>"));
|
Value.Replace(_T("\n"),_T("<LF>"));
|
|
ofs << CString2String(Key) << "=" << CString2String(Value) << std::endl;
|
}
|
}
|
ofs.close();
|
|
return 1;
|
};
|
|
int LoadFromFile(CString FilePathName)
|
{
|
this->Empty();
|
|
std::string filename = CString2String(FilePathName);
|
std::ifstream ifs(filename);
|
if(!ifs.is_open())
|
{
|
std::cerr << "Load MHash error, open file" << filename << " fail." << std::endl;
|
return -1;
|
}
|
|
std::string segment;
|
std::string line;
|
size_t line_count=0;
|
while (std::getline(ifs, line)) {
|
//to skip BOM
|
if (line_count++ == 0 && line.size() > 3) {
|
if (static_cast<unsigned char>(line[0]) == 0xEF &&
|
static_cast<unsigned char>(line[1]) == 0xBB &&
|
static_cast<unsigned char>(line[2]) == 0xBF)
|
{
|
for (int i = 0; i < 3; i++)
|
{
|
line.erase(line.begin());
|
}
|
}
|
}
|
|
if (line[0] == '#' || line[0] == ';') continue;
|
line = trim(line);
|
if (line.empty()) continue;
|
|
if (line[0] == '[')
|
{
|
segment = trim(line.substr(1,line.length()-2));
|
}
|
else if(segment.length()>0)
|
{
|
size_t n = line.find('=');
|
if (n == std::string::npos)
|
continue;
|
|
std::string k = line.substr(0,n);
|
std::string v = trim(line.substr(n+1, line.length()-n-1));
|
|
CString Value = String2CString(v);
|
Value.Replace(_T("<CR><LF>"),_T("\r\n"));
|
Value.Replace(_T("<CR>"),_T("\r"));
|
Value.Replace(_T("<LF>"),_T("\n"));
|
this->operator [](segment.c_str())[k.c_str()] = Value;
|
}
|
}
|
ifs.close();
|
|
return TotalSegment;
|
}
|
};
|
|
typedef void DiffCallBack(const CString& section, const CString& key, const CString oldValue, const CString newValue);
|
|
//±È½ÏÁ½¸öHashµÄÇø±ð,µÚ¶þ¸ö¿ÉÄÜÔÚµÚÒ»¸öµÄ»ù´¡ÉÏÓбä¸ü
|
inline void HashDiff(Hash& h1, Hash& h2, DiffCallBack callback)
|
{
|
CString s1;
|
|
for (int i=0; i<h2.TotalKey; ++i)
|
{
|
CString key = *(h2.elements[i].Key);
|
CString value1 = *(h1[key].Value);
|
CString value2 = *(h2.elements[i].Value);
|
if (value1.GetLength()>256 || value2.GetLength()>256)
|
{
|
continue;
|
}
|
if (0!=value1.CompareNoCase(value2))
|
{
|
callback(h2.Name, key, value1, value2);
|
}
|
}
|
}
|
//±È½ÏÁ½¸öMHashµÄÇø±ð,µÚ¶þ¸ö¿ÉÄÜÔÚµÚÒ»¸öµÄ»ù´¡ÉÏÓбä¸ü
|
inline void MHashDiff(MHash& mh1, MHash& mh2, DiffCallBack callback)
|
{
|
for (int i=0; i<mh2.TotalSegment; ++i)
|
{
|
HashDiff(mh1[mh2.elements[i].SegmentName], *(mh2.elements[i].Segment), callback);
|
}
|
}
|
|