QuakeGod
2022-01-16 326d3e312c74726814c39c9d112faab03c4a167c
提交 | 用户 | age
4b03ae 1 #pragma once
Q 2 /*
3 * HashTable File
4 * Version 1.22 2019-02-25
5 * Description:
6 *
7 *
8 */
9
10 #include <string>
11 #include <iostream>
12 #include <fstream>
13 #include "../Utils.h"
14
15 inline std::string trim(const std::string& s)
16 {
17     char p[] = " \t\r\n";
18     long sp = 0;
19     long ep = (long)s.length() - 1;
20     for (; sp <= ep; ++sp)
21         if (!strchr(p, s[sp])) break;
22     for (; ep >= 0; --ep)
23         if (!strchr(p, s[ep])) break;
24     return s.substr(sp, ep-sp+1);
25 }
26 //struct stCfgCtrl        //配置文件项和控件对应关系
27 //{
28 //    CStringA sKeyName;
29 //    UINT nCtrlId;
30 //};
31 enum enVtype        //变量类型
32 {
33     vtNone = 0,
34     vtbool =1,
35     vtInt = 2,
36     vtFloat = 3,
37     vtDouble = 4,
38     vtString = 5,
39 };
40 enum enCType        //控件类型 
41 {
42     ctNone =0,
43     ctStatic=1,
44     ctEdit=2,
45     ctCheckBox=3,
46     ctRadio=4,
47     ctComboBoxIndex=5,    //ComboBox Index;
48     ctComboBoxString = 6, // ComboBox String;
49     ctListBox = 6,
50     ctListCtrl=7,
51 };
52 struct stCfgValCtrl        //配置文件项和变量以及控件对应关系
53 {
54     CStringA sKeyName;
55     int vType;
56     void * var;
57     UINT nCtrlId;
58     int cType;
59 };
60 template <typename T, size_t N>
61 char(&_ArraySizeHelper(T(&array)[N]))[N];
62 #define countof(array) (sizeof(_ArraySizeHelper(array)))
63
64 #define MAX_HASH_KEY 3000
65 #define MAX_MHASH_SEGMENT 300
66 class Hashelement
67 {
68 public:
69     int HashValue;
70     CString * Key;
71     CString * Value;
72     Hashelement()
73     {
74         HashValue = 0;
75         Key = NULL;
76         Value = NULL;
77     }
78     ~Hashelement()
79     {
80         delete Key;
81         delete Value;
82         Key = NULL;
83         Value = NULL;
84     }
85     Hashelement(const Hashelement& elem)
86     {
87         *this = elem;
88     }
89     Hashelement& operator = (const Hashelement& elem)
90     {
91         if (this == &elem)
92         {
93             return *this;
94         }
95         HashValue = elem.HashValue;
96
97         delete Key;
98         delete Value;    
99         Key = new CString(*(elem.Key));
100         Value = new CString(*(elem.Value));
101         
102         return *this;
103     }
104     operator int ()
105     {
106         return _tstoi(*Value);
107     }
108     operator float()
109     {
110         return float(_tstof(*Value));
111     }
112     operator double()
113     {
114         return _tstof(*Value);
115     }
116     operator LPCTSTR()
117     {
118         return *Value;
119     }
120     //operator CString()
121     //{
122     //    return *Value;
123     //}
124
125     //operator TCHAR *()
126     //{
127     //    return *Value;
128     //}
129     int operator =(int i)
130     {
131         if (Value == nullptr) { Value = new CString; }
132         (*Value).Format(_T("%d"),i);
133         return i;
134     }
135     float operator =(float f)
136     {
137         if (Value == nullptr) { Value = new CString; }
138         (*Value).Format(_T("%f"), f);
139         return f;
140     }
141     double operator =(double d)
142     {
143         if (Value == nullptr) { Value = new CString; }
144         (*Value).Format(_T("%f"), d);
145         return d;
146     }
147     CString operator =(CString s)
148     {
149         if (Value == nullptr) { Value = new CString; }
150         *Value = s;
151         return s;
152     }
153
154 };
155
156 class Hash
157 {
158 public:
159
160     CString Name;
161     int TotalKey;
162     Hashelement elements[MAX_HASH_KEY];
163     
164     Hashelement OverFlow;
165 public:
166
167     Hash::~Hash()
168     {
169     }
170
171     Hash::Hash(void)
172     {
173         TotalKey=0;
174         OverFlow = _T("OverFlow");
175     };
176     Hash::Hash(CString thisName)
177     {
178         TotalKey=0;
179         this->Name=thisName;
180         OverFlow = _T("OverFlow");
181     };
182     Hash(const Hash& hash)
183     {
184         *this = hash;
185         OverFlow = _T("OverFlow");
186     }
187
188     Hash& operator = (const Hash& hash)
189     {
190         if (this == &hash)
191         {
192             return *this;
193         }
194         Name = hash.Name;
195         TotalKey = hash.TotalKey;
196         for (int i=0; i<TotalKey; ++i)
197         {
198             elements[i] = hash.elements[i];
199         }
200         return *this;
201     }
202     void Empty(void)
203     {
204         int i;
205         for (i=0;i<this->TotalKey;i++)
206         {
207             delete elements[i].Key;
208             delete elements[i].Value;
209         }
210         TotalKey=0;
211     }
212
213     Hashelement & Hash::operator [] (const char * str)
214     {
215         CString s1(str);
216         return this->operator [] (s1);
217     };
218     Hashelement & Hash::operator [] (CString s)
219     {
220         int left = 0;
221         int right = TotalKey - 1;
222         int mid;
223
224         int index = -1;
225         while (left <= right)
226         {
227             mid = (left + right) / 2;
228             int r = elements[mid].Key->CompareNoCase(s);
229             if (r < 0)
230             {//key在右边
231                 left = mid + 1;
232             } else if (r > 0)
233             {//key在左边
234                 right = mid - 1;
235             } else
236             {
237                 index = mid;
238                 break;
239             }
240         }
241
242         if (index == -1 && TotalKey < MAX_HASH_KEY)
243         {
244             index = left;
245             for (int i = TotalKey; i > index; --i)
246             {
247                 elements[i].Key = elements[i-1].Key;
248                 elements[i].Value = elements[i-1].Value;
249             }
250
251             elements[index].Key = new CString(s);
252             elements[index].Value = new CString(s);
253             TotalKey++;
254         }
255
256         if (index==-1)
257         {
258             return OverFlow;
259         }
260
261         return elements[index];
262     };
263     Hashelement & Hash::operator [] (int k)
264     {
265         return elements[k];
266     };
267
268     template <typename T, size_t N>
269     int inline SetVarList(T(&pCfgs)[N])
270     {
271         return SetVarList(pCfgs, N);
272     }
273
274     int SetVarList(stCfgValCtrl *pCfgs, int nCount)
275     {
276         for (int i = 0; i < nCount; i++)
277         {
278             int vtype = pCfgs[i].vType;
279             void * pvar = pCfgs[i].var;
280             int nCtrlId = pCfgs[i].nCtrlId;
281             if (pvar==nullptr) continue;
282
283             switch (vtype)
284             {
285             case vtbool:
286             case vtInt: *(int *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
287             case vtFloat:*(float *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
288             case vtDouble:*(double *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
289             case vtString:*(CString *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
290             default:
291                 break;
292             }
293         }
294         return nCount;
295     }
296     int SetCtrl(const char * str, CWnd * pWnd, int nCtrlId, int nCtrlType)
297     {
298         CString s1(str);
299         return SetCtrl(s1, pWnd, nCtrlId,nCtrlType);
300     }
301     int SetCtrl(CString str, CWnd * pWnd, int nCtrlId, int nCtrlType)
302     {
303         if (nCtrlId == 0) return 0;
304         CWnd * pCtrl = pWnd->GetDlgItem(nCtrlId);
305         if (pCtrl == nullptr) return -1;
306         switch (nCtrlType)
307         {
308         case ctEdit:    
309             pWnd->SetDlgItemText(nCtrlId, this->operator [] (str)); break;
310         case ctCheckBox:   
311             ((CButton *)pCtrl)->SetCheck(this->operator [] (str)); break;
312         case ctComboBoxIndex: 
313             ((CComboBox*)pCtrl)->SetCurSel(this->operator [] (str)); break;
314         case ctComboBoxString:
315             ((CComboBox*)pCtrl)->SelectString(0,this->operator [] (str));
316             pWnd->SetDlgItemText(nCtrlId, this->operator [] (str)); break;
317         default:
318             break;
319         }
320         return 0;
321     }
322
323     template <typename T,size_t N>
324     int inline SetCtrlList(CWnd * pWnd, T (&pCfgs)[N])
325     {
326         return SetCtrlList(pWnd, pCfgs, N);
327     }
328
329     int SetCtrlList(CWnd * pWnd, stCfgValCtrl * pCfgs, int nCount)
330     {
331         for (int i = 0; i < nCount; i++)
332         {
333
334             int vtype = pCfgs[i].vType;
335             void * pvar = pCfgs[i].var;
336             int nCtrlId = pCfgs[i].nCtrlId;
337             int  nCtrlType = pCfgs[i].cType;
338             SetCtrl(pCfgs[i].sKeyName, pWnd, nCtrlId,nCtrlType);
339
340             if (pvar == nullptr) continue;
341             switch (vtype)
342             {
343             case vtbool: 
344             case vtInt: *(int *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
345             case vtFloat:*(float *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
346             case vtDouble:*(double *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
347             case vtString:*(CString *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
348             default:
349                 break;
350             }
351
352         }
353         return nCount;
354     }
355     template <typename T, size_t N>
356     int inline GetCtrlList(CWnd * pWnd, T(&pCfgs)[N])
357     {
358         return GetCtrlList(pWnd, pCfgs, N);
359     }
360
361     int GetCtrl(const char * str, CWnd * pWnd, int nCtrlId, int nCtrlType)
362     {
363         CString s1(str);
364         return GetCtrl(s1, pWnd, nCtrlId, nCtrlType);
365     }
366     int GetCtrl(CString str, CWnd * pWnd, int nCtrlId, int nCtrlType)
367     {
368         if (nCtrlId == 0) return 0;
369         CString s1;
370         CWnd * pCtrl = pWnd->GetDlgItem(nCtrlId);
371         if (pCtrl == nullptr) return -1;
372
373         switch (nCtrlType)
374         {
375         case ctEdit:    
376             pWnd->GetDlgItemText(nCtrlId, s1); this->operator [] (str) = s1; break;
377         case ctCheckBox:   
378             this->operator [] (str) = ((CButton *)pCtrl)->GetCheck(); break;
379         case ctComboBoxIndex:
380             this->operator [] (str)=((CComboBox *)pCtrl)->GetCurSel();     break;
381         case ctComboBoxString:
382             pWnd->GetDlgItemText(nCtrlId, s1); this->operator [] (str) = s1; break;
383
384         default:
385             break;
386         }
387         return 0;
388     }
389
390     int GetCtrlList(CWnd * pWnd, stCfgValCtrl * pCfgs, int nCount)
391     {
392         for (int i = 0; i < nCount; i++)
393         {
394             int vtype = pCfgs[i].vType;
395             void * pvar = pCfgs[i].var;
396             int nCtrlId = pCfgs[i].nCtrlId;
397             int  nCtrlType = pCfgs[i].cType;
398             GetCtrl(pCfgs[i].sKeyName, pWnd, nCtrlId,nCtrlType);
399
400             if (pvar == nullptr) continue;
401             switch (vtype)
402             {
403             case vtbool:
404             case vtInt: *(int *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
405             case vtFloat:*(float *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
406             case vtDouble:*(double *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
407             case vtString:*(CString *)pvar = this->operator [] (pCfgs[i].sKeyName); break;
408             default:
409                 break;
410             }
411
412         }
413         return nCount;
414     }
415     int Hash::SaveToFile(CString FilePathName,CString Section)
416     {
417         int i;
418         CString Key,Value;
419         CString CurrentDirectory;
420
421         for (i=0;i<TotalKey;i++)
422         {
423             Key=*(elements[i].Key);
424             Value=*(elements[i].Value);
425             Value.Replace(_T("\r\n"),_T("<CR><LF>"));
426             Value.Replace(_T("\r"),_T("<CR>"));
427             Value.Replace(_T("\n"),_T("<LF>"));
428             WritePrivateProfileString(Section,Key,Value,FilePathName);
429         }
430         return 1;
431     };
432
433     int Hash::LoadFromFile(CString FilePathName,CString Section)
434     {
435         CString Key;
436         CString value,value1,value2;
437         CString Defaultstr;
438         Defaultstr=_T("");
439         int k,l;
440         CString s1,s2,s3;
441         k=GetPrivateProfileString(NULL,NULL,Defaultstr,value1.GetBuffer(40960),40960,FilePathName);
442         value1.ReleaseBuffer(k);
443         TCHAR * p2;
444         int n1,n2,n3;
445         n3=GetPrivateProfileString(Section,NULL,Defaultstr,value2.GetBuffer(40960),40960,FilePathName);
446         for (n1=0;n1<n3;n1++)
447         {
448             p2=s3.GetBuffer(40960);
449             for (n2=0;;n2++)
450             {
451                 if (value2.GetString()[n1+n2])
452                 {p2[n2]=(value2.GetString())[n1+n2];}
453                 else
454                 {break;}
455             }
456             s3.ReleaseBuffer(n2);
457
458             Key=s3;
459
460             l=GetPrivateProfileString(Section,Key,Defaultstr,value.GetBuffer(40960),40960,FilePathName);
461             value.ReleaseBuffer();
462             value.Replace(_T("<CR><LF>"),_T("\r\n"));
463             value.Replace(_T("<CR>"),_T("\r"));
464             value.Replace(_T("<LF>"),_T("\n"));
465             this->operator [](Key)=value;
466             n1+=n2;
467         }
468         return 1;
469     };
470 };
471
472 class MHashelement
473 {
474 public:
475     int HashValue;
476     CString SegmentName;
477     Hash * Segment;
478
479     MHashelement()
480     {
481         HashValue = 0;
482         SegmentName = _T("");
483         Segment = NULL;
484     }
485
486     ~MHashelement()
487     {
488         delete Segment;
489         Segment = NULL;
490     }
491
492     MHashelement(const MHashelement& elem)
493     {
494         *this = elem;
495     }
496     MHashelement& operator = (const MHashelement& elem)
497     {
498         if (this == &elem)
499         {
500             return *this;
501         }
502         HashValue = elem.HashValue;
503         SegmentName = elem.SegmentName;
504
505         delete Segment;
506         Segment = new Hash(*(elem.Segment));
507
508         return *this;
509     };
510 };
511 class MHash
512 {
513 public:
514     int TotalSegment;
515     MHashelement elements[MAX_MHASH_SEGMENT];
516
517     Hash OverFlow;
518     ~MHash()
519     {
520     };
521
522     MHash(void)
523     {
524         TotalSegment=0;
525         OverFlow = Hash(_T("OverFlow"));
526     };
527
528     MHash(const MHash& mhash)
529     {
530         *this = mhash;
531         OverFlow = Hash(_T("OverFlow"));
532     }
533
534     MHash& operator = (const MHash& mhash)
535     {
536         if (this == &mhash)
537         {
538             return *this;
539         }
540         TotalSegment=mhash.TotalSegment;
541         for (int i=0;i<TotalSegment;i++)
542         {
543             elements[i] = mhash.elements[i];
544         }
545         return *this;
546     }
547     void Empty()
548     {
549         int i;
550         for (i=0;i<TotalSegment;i++)
551         {
552             delete elements[i].Segment;
553         }
554         TotalSegment=0;
555     }
556     Hash & operator [] (const char * str)
557     {
558         CString s1(str);
559         return this->operator [] (s1);
560     };
561     
562     Hash & operator [] (CString s)
563     {
564         int left = 0;
565         int right = TotalSegment - 1;
566         int mid;
567
568         int index = -1;
569         while (left <= right)
570         {
571             mid = (left + right) / 2;
572             int r = elements[mid].SegmentName.CompareNoCase(s);
573             if (r < 0)
574             {//key在右边
575                 left = mid + 1;
576             } else if (r > 0)
577             {//key在左边
578                 right = mid - 1;
579             } else
580             {
581                 index = mid;
582                 break;
583             }
584         }
585
586         if (index == -1 && TotalSegment < MAX_MHASH_SEGMENT)
587         {
588             index = left;
589             for (int i = TotalSegment; i > index; --i)
590             {
591                 elements[i].Segment = elements[i-1].Segment;
592                 elements[i].SegmentName = elements[i-1].SegmentName;
593             }
594             elements[index].Segment= new Hash(s);
595             elements[index].SegmentName = s;
596             TotalSegment++;
597         }
598         
599         if (index==-1)
600         {
601             return OverFlow;
602         }
603         
604         return *(elements[index].Segment);
605     };
606     Hash & operator [] (int k)
607     {
608         return *(elements[k].Segment);
609     };
610
611     int SaveToFileOld(CString FilePathName)
612     {
613         int i,j;
614         CString Section;
615         CString Key,Value;
616         CString CurrentDirectory;
617
618         for (i=0;i<TotalSegment;i++)
619         {
620             Section=elements[i].SegmentName;
621             for (j=0;j<this->operator [](i).TotalKey;j++)
622             {
623                 Key=*(this->operator [](i).elements[j].Key) ;
624                 Value=*(this->operator [](i).elements[j].Value);
625                 Value.Replace(_T("\r\n"),_T("<CR><LF>"));
626                 Value.Replace(_T("\r"),_T("<CR>"));
627                 Value.Replace(_T("\n"),_T("<LF>"));
628                 WritePrivateProfileString(Section,Key,Value,FilePathName);
629             }
630         }
631         return 1;
632     };
633
634     int LoadFromFileOld(CString FilePathName)
635     {
636         CString Key;
637         CString Value,value1,value2;
638         CString Section;
639         CString Defaultstr;
640         Defaultstr=_T("");
641         this->Empty();
642         int i,j,k,l;
643         CString s1,s2,s3;
644         k=GetPrivateProfileString(NULL,NULL,Defaultstr,value1.GetBuffer(40960),40960,FilePathName);
645         value1.ReleaseBuffer(k);
646         TCHAR * p1;
647         TCHAR * p2;
648         int n1,n2,n3;
649         for (i=0;i<k;i++)
650         {
651             p1=s2.GetBuffer(40960);
652             for (j=0;;j++)
653             {
654                 if ((value1.GetString())[i+j])
655                 {p1[j]=((LPTSTR)value1.GetString())[i+j];}
656                 else
657                 {    break;}
658             }
659             s2.ReleaseBuffer(j);
660             Section=s2;
661             n3=GetPrivateProfileString(Section,NULL,Defaultstr,value2.GetBuffer(40960),40960,FilePathName);
662
663             for (n1=0;n1<n3;n1++)
664             {
665                 p2=s3.GetBuffer(40960);
666                 for (n2=0;;n2++)
667                 {
668                     if (value2.GetString()[n1+n2])
669                     {p2[n2]=(value2.GetString())[n1+n2];}
670                     else
671                     {break;}
672                 }
673                 s3.ReleaseBuffer(n2);
674
675                 Key=s3;
676
677                 l=GetPrivateProfileString(Section,Key,Defaultstr,Value.GetBuffer(40960),40960,FilePathName);
678                 Value.ReleaseBuffer();
679                 Value.Replace(_T("<CR><LF>"),_T("\r\n"));
680                 Value.Replace(_T("<CR>"),_T("\r"));
681                 Value.Replace(_T("<LF>"),_T("\n"));
682                 this->operator [](Section)[Key]=Value;
683                 n1+=n2;
684             }
685
686             i+=j;        
687         }
688
689         return k;
690     };
691
692     int SaveToFile(CString FilePathName)
693     {
694         std::string filename = CString2String(FilePathName);
695         std::ofstream ofs(filename);
696         if (!ofs.is_open())
697         {
698             std::cerr << "Save MHash error, open file" << filename << " fail." << std::endl;
699             return -1;
700         }
701
702         int i,j;
703         CString Section;
704         CString Key,Value;
705
706         for (i=0;i<TotalSegment;i++)
707         {
708             Section=elements[i].SegmentName;
709             ofs << "[" << CString2String(Section) << "]" << std::endl;
710
711             for (j=0;j<this->operator [](i).TotalKey;j++)
712             {
713                 Key=*(this->operator [](i).elements[j].Key) ;
714                 Value=*(this->operator [](i).elements[j].Value);
715                 Value.Replace(_T("\r\n"),_T("<CR><LF>"));
716                 Value.Replace(_T("\r"),_T("<CR>"));
717                 Value.Replace(_T("\n"),_T("<LF>"));
718
719                 ofs << CString2String(Key) << "=" << CString2String(Value) << std::endl;
720             }
721         }
722         ofs.close();
723
724         return 1;
725     };
726
727     int LoadFromFile(CString FilePathName)
728     {
729         this->Empty();
730
731         std::string filename = CString2String(FilePathName);
732         std::ifstream ifs(filename);
733         if(!ifs.is_open())
734         {
735             std::cerr << "Load MHash error, open file" << filename << " fail." << std::endl;
736             return -1;
737         }
738
739         std::string segment;
740         std::string line;
741         size_t line_count=0;
742         while (std::getline(ifs, line)) {
743             //to skip BOM
744             if (line_count++ == 0 && line.size() > 3) {
745                 if (static_cast<unsigned char>(line[0]) == 0xEF &&
746                     static_cast<unsigned char>(line[1]) == 0xBB &&
747                     static_cast<unsigned char>(line[2]) == 0xBF)
748                 {
749                     for (int i = 0; i < 3; i++)
750                     {
751                         line.erase(line.begin());
752                     }
753                 }
754             }
755
756             if (line[0] == '#' || line[0] == ';') continue;
757             line = trim(line);
758             if (line.empty()) continue;
759
760             if (line[0] == '[')
761             {
762                 segment = trim(line.substr(1,line.length()-2));
763             }
764             else if(segment.length()>0)
765             {
766                 size_t n = line.find('=');
767                 if (n == std::string::npos)
768                     continue;
769
770                 std::string k = line.substr(0,n);
771                 std::string v = trim(line.substr(n+1, line.length()-n-1));
772
773                 CString Value = String2CString(v);
774                 Value.Replace(_T("<CR><LF>"),_T("\r\n"));
775                 Value.Replace(_T("<CR>"),_T("\r"));
776                 Value.Replace(_T("<LF>"),_T("\n"));
777                 this->operator [](segment.c_str())[k.c_str()] = Value;
778             }
779         }
780         ifs.close();
781
782         return TotalSegment;
783     }
784 };
785
786 typedef void DiffCallBack(const CString& section, const CString& key, const CString oldValue, const CString newValue);
787
788 //比较两个Hash的区别,第二个可能在第一个的基础上有变更
789 inline void HashDiff(Hash& h1, Hash& h2, DiffCallBack callback)
790 {
791     CString s1;
792     
793     for (int i=0; i<h2.TotalKey; ++i)
794     {
795         CString key = *(h2.elements[i].Key);
796         CString value1 = h1[key];
797         CString value2 = *(h2.elements[i].Value);
798         if (value1.GetLength()>256 || value2.GetLength()>256)
799         {
800             continue;
801         }
802         if (0!=value1.CompareNoCase(value2))
803         {
804             callback(h2.Name, key, value1, value2);
805         }
806     }
807 }
808 //比较两个MHash的区别,第二个可能在第一个的基础上有变更
809 inline void MHashDiff(MHash& mh1, MHash& mh2, DiffCallBack callback)
810 {
811     for (int i=0; i<mh2.TotalSegment; ++i)
812     {
813         HashDiff(mh1[mh2.elements[i].SegmentName], *(mh2.elements[i].Segment), callback);
814     }
815 }
816