Rev Author Line No. Line
2061 mija 1 /////////////////////////////////////////////////////////////////////////////////
2 // Cini Class Implementation
3 /////////////////////////////////////////////////////////////////////////////////
4 #include "stdafx.h" // include if you got "fatal error C1010: unexpected end of file..."
5 #include "Ini.h"
6 #include <string.h>
7 #include <stdio.h>
8 #include <assert.h>
9  
10 #define DEF_PROFILE_NUM_LEN 64 // numeric string length, could be quite long for binary format
11 #define DEF_PROFILE_THRESHOLD 512 // temporary string length
12 #define DEF_PROFILE_DELIMITER _T(",") // default string delimiter
13 #define DEF_PROFILE_TESTSTRING _T("{63788286-AE30-4D6B-95DF-3B451C1C79F9}") // Uuid for internal use
14  
15 // struct used to be passed to __KeyPairProc as a LPVOID parameter
16 struct STR_LIMIT
17 {
18 LPTSTR lpTarget;
19 DWORD dwRemain;
20 DWORD dwTotalCopied;
21 };
22  
23 /////////////////////////////////////////////////////////////////////////////////
24 // Constructors & Destructor
25 /////////////////////////////////////////////////////////////////////////////////
26 CIni::CIni()
27 {
28 m_pszPathName = NULL;
29 }
30  
31 CIni::CIni(LPCTSTR lpPathName)
32 {
33 m_pszPathName = NULL;
34 SetPathName(lpPathName);
35 }
36  
37 CIni::~CIni()
38 {
39 if (m_pszPathName != NULL)
40 delete [] m_pszPathName;
41 }
42  
43 /////////////////////////////////////////////////////////////////////////////////
44 // Ini File Path Access
45 /////////////////////////////////////////////////////////////////////////////////
46  
47 // Assign ini file path name
48 void CIni::SetPathName(LPCTSTR lpPathName)
49 {
50 if (lpPathName == NULL)
51 {
52 if (m_pszPathName != NULL)
53 *m_pszPathName = _T('\0');
54 }
55 else
56 {
57 if (m_pszPathName != NULL)
58 delete [] m_pszPathName;
59  
60 m_pszPathName = _tcsdup(lpPathName);
61 }
62 }
63  
64 // Retrieve ini file path name
65 DWORD CIni::GetPathName(LPTSTR lpBuffer, DWORD dwBufSize) const
66 {
67 *lpBuffer = _T('\0');
68 DWORD dwLen = 0;
69 if (lpBuffer != NULL)
70 {
71 _tcsncpy(lpBuffer, m_pszPathName, dwBufSize);
72 dwLen = _tcslen(lpBuffer);
73 }
74 else
75 {
76 // just calculate the required buffer size
77 dwLen = _tcslen(m_pszPathName);
78 }
79 return dwLen;
80 }
81  
82 #ifdef __AFXWIN_H__
83 CString CIni::GetPathName() const
84 {
85 return CString(m_pszPathName);
86 }
87 #endif
88  
89 /////////////////////////////////////////////////////////////////////////////////
90 // Raw String Access
91 /////////////////////////////////////////////////////////////////////////////////
92  
93 // Get a profile string value, if the buffer size is not large enough, the result
94 // may be truncated.
95 DWORD CIni::GetString(LPCTSTR lpSection, LPCTSTR lpKey, LPTSTR lpBuffer, DWORD dwBufSize, LPCTSTR lpDefault) const
96 {
97 if (lpBuffer != NULL)
98 *lpBuffer = _T('\0');
99  
100 LPTSTR psz = __GetStringDynamic(lpSection, lpKey, lpDefault);
101 DWORD dwLen = _tcslen(psz);
102  
103 if (lpBuffer != NULL)
104 {
105 _tcsncpy(lpBuffer, psz, dwBufSize);
106 dwLen = min(dwLen, dwBufSize);
107 }
108  
109 delete [] psz;
110 return dwLen;
111 }
112  
113 #ifdef __AFXWIN_H__
114 CString CIni::GetString(LPCTSTR lpSection, LPCTSTR lpKey, LPCTSTR lpDefault) const
115 {
116 LPTSTR psz = __GetStringDynamic(lpSection, lpKey, lpDefault);
117 CString str(psz);
118 delete [] psz;
119 return str;
120 }
121 #endif
122  
123 // Write a string value to the ini file
124 BOOL CIni::WriteString(LPCTSTR lpSection, LPCTSTR lpKey, LPCTSTR lpValue) const
125 {
126 if (lpSection == NULL || lpKey == NULL)
127 return FALSE;
128  
129 return ::WritePrivateProfileString(lpSection, lpKey, lpValue == NULL ? _T("") : lpValue, m_pszPathName);
130 }
131  
132 // Read a string value from the ini file, append another string after it and then write it
133 // back to the ini file
134 BOOL CIni::AppendString(LPCTSTR lpSection, LPCTSTR lpKey, LPCTSTR lpString) const
135 {
136 if (lpString == NULL)
137 return FALSE;
138  
139 TCHAR* psz = __GetStringDynamic(lpSection, lpKey);
140 TCHAR* pNewString = new TCHAR[_tcslen(psz) + _tcslen(lpString) + 1];
141 _stprintf(pNewString, _T("%s%s"), psz, lpString);
142 const BOOL RES = WriteString(lpSection, lpKey, pNewString);
143 delete [] pNewString;
144 delete [] psz;
145 return RES;
146 }
147  
148 /////////////////////////////////////////////////////////////////////////////////
149 // Ini File String Array Access
150 /////////////////////////////////////////////////////////////////////////////////
151  
152 // Get an array of string
153 DWORD CIni::GetArray(LPCTSTR lpSection, LPCTSTR lpKey, LPTSTR lpBuffer, DWORD dwBufSize, LPCTSTR lpDelimiter, BOOL bTrimString) const
154 {
155 if (lpBuffer != NULL)
156 *lpBuffer = _T('\0');
157  
158 if (lpSection == NULL || lpKey == NULL)
159 return 0;
160  
161 LPTSTR psz = __GetStringDynamic(lpSection, lpKey);
162  
163 DWORD dwCopied = 0;
164  
165 if (*psz != _T('\0'))
166 {
167 if (lpBuffer == NULL)
168 {
169 // just calculate the required buffer size
170 const DWORD MAX_LEN = _tcslen(psz) + 2;
171 LPTSTR p = new TCHAR[MAX_LEN + 1];
172 dwCopied = __StringSplit(psz, p, MAX_LEN, lpDelimiter, bTrimString);
173 delete [] p;
174 }
175 else
176 {
177 dwCopied = __StringSplit(psz, lpBuffer, dwBufSize, lpDelimiter, bTrimString);
178 }
179 }
180  
181 delete [] psz;
182 return dwCopied;
183 }
184  
185 #ifdef __AFXWIN_H__
186 void CIni::GetArray(LPCTSTR lpSection, LPCTSTR lpKey, CStringArray *pArray, LPCTSTR lpDelimiter, BOOL bTrimString) const
187 {
188 if (pArray != NULL)
189 pArray->RemoveAll();
190  
191 const DWORD LEN = GetArray(lpSection, lpKey, NULL, 0, lpDelimiter);
192 if (LEN == 0)
193 return;
194  
195 LPTSTR psz = new TCHAR[LEN + 3];
196 GetArray(lpSection, lpKey, psz, LEN + 2, lpDelimiter);
197 ParseDNTString(psz, __SubStrAdd, (LPVOID)pArray);
198 delete [] psz;
199 }
200 #endif
201  
202 #ifdef __AFXWIN_H__
203 BOOL CIni::WriteArray(LPCTSTR lpSection, LPCTSTR lpKey, const CStringArray *pArray, int nWriteCount, LPCTSTR lpDelimiter) const
204 {
205 if (pArray == NULL)
206 return FALSE;
207  
208 if (nWriteCount < 0)
209 nWriteCount = pArray->GetSize();
210 else
211 nWriteCount = min(nWriteCount, pArray->GetSize());
212  
213 const CString DELIMITER = (lpDelimiter == NULL || *lpDelimiter == _T('\0')) ? _T(",") : lpDelimiter;
214 CString sLine;
215 for (int i = 0; i < nWriteCount; i++)
216 {
217 sLine += pArray->GetAt(i);
218 if (i != nWriteCount - 1)
219 sLine += DELIMITER;
220 }
221 return WriteString(lpSection, lpKey, sLine);
222 }
223 #endif
224  
225 /////////////////////////////////////////////////////////////////////////////////
226 // Primitive Data Type Access
227 /////////////////////////////////////////////////////////////////////////////////
228  
229 // Get a signed integral value
230 int CIni::GetInt(LPCTSTR lpSection, LPCTSTR lpKey, int nDefault, int nBase) const
231 {
232 TCHAR sz[DEF_PROFILE_NUM_LEN + 1] = _T("");
233 GetString(lpSection, lpKey, sz, DEF_PROFILE_NUM_LEN);
234 return *sz == _T('\0') ? nDefault : int(_tcstoul(sz, NULL, __ValidateBase(nBase)));
235 }
236  
237 // Get an unsigned integral value
238 UINT CIni::GetUInt(LPCTSTR lpSection, LPCTSTR lpKey, UINT nDefault, int nBase) const
239 {
240 TCHAR sz[DEF_PROFILE_NUM_LEN + 1] = _T("");
241 GetString(lpSection, lpKey, sz, DEF_PROFILE_NUM_LEN);
242 return *sz == _T('\0') ? nDefault : UINT(_tcstoul(sz, NULL, __ValidateBase(nBase)));
243 }
244  
245 // Get a boolean value
246 BOOL CIni::GetBool(LPCTSTR lpSection, LPCTSTR lpKey, BOOL bDefault) const
247 {
248 TCHAR sz[DEF_PROFILE_NUM_LEN + 1] = _T("");
249 GetString(lpSection, lpKey, sz, DEF_PROFILE_NUM_LEN);
250 return StringToBool(sz, bDefault);
251 }
252  
253 // Get a double floating value
254 double CIni::GetDouble(LPCTSTR lpSection, LPCTSTR lpKey, double fDefault) const
255 {
256 TCHAR sz[DEF_PROFILE_NUM_LEN + 1] = _T("");
257 GetString(lpSection, lpKey, sz, DEF_PROFILE_NUM_LEN);
258 return *sz == _T('\0') ? fDefault : _tcstod(sz, NULL);
259 }
260  
261 // Write a signed integral value to the ini file
262 BOOL CIni::WriteInt(LPCTSTR lpSection, LPCTSTR lpKey, int nValue, int nBase) const
263 {
264 TCHAR szValue[DEF_PROFILE_NUM_LEN + 1] = _T("");
265 __IntToString(nValue, szValue, nBase);
266 return WriteString(lpSection, lpKey, szValue);
267 }
268  
269 // Write an unsigned value to the ini file
270 BOOL CIni::WriteUInt(LPCTSTR lpSection, LPCTSTR lpKey, UINT nValue, int nBase) const
271 {
272 TCHAR szValue[DEF_PROFILE_NUM_LEN + 1] = _T("");
273 __UIntToString(nValue, szValue, nBase);
274 return WriteString(lpSection, lpKey, szValue);
275 }
276  
277 // Write a double floating value to the ini file
278 BOOL CIni::WriteDouble(LPCTSTR lpSection, LPCTSTR lpKey, double fValue, int nPrecision) const
279 {
280 TCHAR szFmt[16] = _T("%f");
281  
282 if (nPrecision > 0)
283 _stprintf(szFmt, _T("%%.%df"), nPrecision);
284  
285 TCHAR szValue[DEF_PROFILE_NUM_LEN + 1] = _T("");
286 _stprintf(szValue, szFmt, fValue);
287 return WriteString(lpSection, lpKey, szValue);
288 }
289  
290 // Read a double value from the ini file, increase it then write it back
291 BOOL CIni::IncreaseDouble(LPCTSTR lpSection, LPCTSTR lpKey, double fIncrease, int nPrecision) const
292 {
293 double f = GetDouble(lpSection, lpKey, 0.0);
294 f += fIncrease;
295 return WriteDouble(lpSection, lpKey, f, nPrecision);
296 }
297  
298 // Write a boolean value to the ini file
299 BOOL CIni::WriteBool(LPCTSTR lpSection, LPCTSTR lpKey, BOOL bValue) const
300 {
301 return WriteInt(lpSection, lpKey, bValue ? 1 : 0, BASE_DECIMAL);
302 }
303  
304 // Read a boolean value from the ini file, invert it(true becomes false, false becomes true),
305 // then write it back
306 BOOL CIni::InvertBool(LPCTSTR lpSection, LPCTSTR lpKey) const
307 {
308 return WriteBool(lpSection, lpKey, !GetBool(lpSection, lpKey, FALSE));
309 }
310  
311 // Read a int from the ini file, increase it and then write it back to the ini file
312 BOOL CIni::IncreaseInt(LPCTSTR lpSection, LPCTSTR lpKey, int nIncrease, int nBase) const
313 {
314 int nVal = GetInt(lpSection, lpKey, 0, nBase);
315 nVal += nIncrease;
316 return WriteInt(lpSection, lpKey, nVal, nBase);
317 }
318  
319 // Read an UINT from the ini file, increase it and then write it back to the ini file
320 BOOL CIni::IncreaseUInt(LPCTSTR lpSection, LPCTSTR lpKey, UINT nIncrease, int nBase) const
321 {
322 UINT nVal = GetUInt(lpSection, lpKey, 0, nBase);
323 nVal += nIncrease;
324 return WriteUInt(lpSection, lpKey, nVal, nBase);
325 }
326  
327 TCHAR CIni::GetChar(LPCTSTR lpSection, LPCTSTR lpKey, TCHAR cDefault) const
328 {
329 TCHAR sz[2] = _T("");
330 GetString(lpSection, lpKey, sz, 1);
331 return *sz == _T('\0') ? cDefault : sz[0];
332 }
333  
334 BOOL CIni::WriteChar(LPCTSTR lpSection, LPCTSTR lpKey, TCHAR c) const
335 {
336 TCHAR sz[2] = { c, _T('\0') };
337 return WriteString(lpSection, lpKey, sz);
338 }
339  
340 /////////////////////////////////////////////////////////////////////////////////
341 // User-Defined Data Type Access
342 /////////////////////////////////////////////////////////////////////////////////
343  
344 // Get a block of raw data from the ini file
345 DWORD CIni::GetDataBlock(LPCTSTR lpSection, LPCTSTR lpKey, LPVOID lpBuffer, DWORD dwBufSize, DWORD dwOffset) const
346 {
347 LPTSTR psz = __GetStringDynamic(lpSection, lpKey);
348 DWORD dwLen = _tcslen(psz) / 2;
349 if (dwLen <= dwOffset)
350 {
351 delete [] psz;
352 return 0;
353 }
354  
355 // verify psz, must be all in hex format
356 for (int i = 0; psz[i] != _T('\0'); i++)
357 {
358 TCHAR c = psz[i];
359 if ((c >= _T('0') && c <= _T('9'))
360 || (c >= _T('a') && c <= _T('f'))
361 || (c >= _T('A') && c <= _T('F')))
362 {
363 // valid
364 }
365 else
366 {
367 delete [] psz;
368 return 0;
369 }
370 }
371  
372 DWORD dwProcLen = 0;
373 LPBYTE lpb = (LPBYTE)lpBuffer;
374  
375 if (lpb != NULL)
376 {
377 dwProcLen = min(dwLen - dwOffset, dwBufSize);
378 LPCTSTR p = &psz[dwOffset * 2];
379 for (DWORD i = 0; i < dwProcLen; i++)
380 {
381 TCHAR sz[3] = _T("");
382 _tcsncpy(sz, p, 2);
383 lpb[i] = BYTE(_tcstoul(sz, NULL, 16));
384 p = &p[2];
385 }
386 }
387 else
388 {
389 dwProcLen = dwLen - dwOffset;
390 }
391 delete [] psz;
392 return dwProcLen;
393 }
394  
395 // Write a block of raw data to the ini file
396 BOOL CIni::WriteDataBlock(LPCTSTR lpSection, LPCTSTR lpKey, LPCVOID lpData, DWORD dwDataSize) const
397 {
398 const BYTE* lpb = (const BYTE*)lpData;
399 if (lpb == NULL)
400 return FALSE;
401  
402 LPTSTR psz = new TCHAR[dwDataSize * 2 + 1];
403 for (DWORD i = 0, j = 0; i < dwDataSize; i++, j += 2)
404 _stprintf(&psz[j], _T("%02X"), lpb[i]);
405 const BOOL RES = WriteString(lpSection, lpKey, psz);
406 delete [] psz;
407 return RES;
408 }
409  
410 // Append a block of raw data to a specified key in the ini file
411 BOOL CIni::AppendDataBlock(LPCTSTR lpSection, LPCTSTR lpKey, LPCVOID lpData, DWORD dwDataSize) const
412 {
413 const BYTE* lpb = (const BYTE*)lpData;
414 if (lpb == NULL)
415 return FALSE;
416  
417 LPTSTR psz = new TCHAR[dwDataSize * 2 + 1];
418 for (DWORD i = 0, j = 0; i < dwDataSize; i++, j += 2)
419 _stprintf(&psz[j], _T("%02X"), lpb[i]);
420 const BOOL RES = AppendString(lpSection, lpKey, psz);
421 delete [] psz;
422 return RES;
423 }
424  
425 // Get a POINT value
426 POINT CIni::GetPoint(LPCTSTR lpSection, LPCTSTR lpKey, POINT ptDefault) const
427 {
428 POINT pt;
429 if (GetDataBlock(lpSection, lpKey, &pt, sizeof(POINT)) != sizeof(POINT))
430 pt = ptDefault;
431 return pt;
432 }
433  
434 // Get a RECT value
435 RECT CIni::GetRect(LPCTSTR lpSection, LPCTSTR lpKey, RECT rcDefault) const
436 {
437 RECT rc;
438 if (GetDataBlock(lpSection, lpKey, &rc, sizeof(RECT)) != sizeof(RECT))
439 rc = rcDefault;
440 return rc;
441 }
442  
443 // Write a POINT to the ini file
444 BOOL CIni::WritePoint(LPCTSTR lpSection, LPCTSTR lpKey, POINT pt) const
445 {
446 return WriteDataBlock(lpSection, lpKey, &pt, sizeof(POINT));
447 }
448  
449 // Write a RECT to the ini file
450 BOOL CIni::WriteRect(LPCTSTR lpSection, LPCTSTR lpKey, RECT rc) const
451 {
452 return WriteDataBlock(lpSection, lpKey, &rc, sizeof(RECT));
453 }
454  
455 /////////////////////////////////////////////////////////////////////////////////
456 // Sections & Keys Access
457 /////////////////////////////////////////////////////////////////////////////////
458  
459 // Retrieve a list of key-lines(key-pairs) of the specified section
460 DWORD CIni::GetKeyLines(LPCTSTR lpSection, LPTSTR lpBuffer, DWORD dwBufSize) const
461 {
462 if (lpBuffer != NULL)
463 *lpBuffer = _T('\0');
464  
465 if (lpSection == NULL)
466 return 0;
467  
468 if (lpBuffer == NULL)
469 {
470 // just calculate the required buffer size
471 DWORD dwLen = DEF_PROFILE_THRESHOLD;
472 LPTSTR psz = new TCHAR[dwLen + 1];
473 DWORD dwCopied = ::GetPrivateProfileSection(lpSection, psz, dwLen, m_pszPathName);
474  
475 while (dwCopied + 2 >= dwLen)
476 {
477 dwLen += DEF_PROFILE_THRESHOLD;
478 delete [] psz;
479 psz = new TCHAR[dwLen + 1];
480 dwCopied = ::GetPrivateProfileSection(lpSection, psz, dwLen, m_pszPathName);
481 }
482  
483 delete [] psz;
484 return dwCopied + 2;
485 }
486 else
487 {
488 return ::GetPrivateProfileSection(lpSection, lpBuffer, dwBufSize, m_pszPathName);
489 }
490 }
491  
492 // Retrieve a list of key names of the specified section
493 DWORD CIni::GetKeyNames(LPCTSTR lpSection, LPTSTR lpBuffer, DWORD dwBufSize) const
494 {
495 if (lpBuffer != NULL)
496 *lpBuffer = _T('\0');
497  
498 if (lpSection == NULL)
499 return 0;
500  
501 STR_LIMIT sl;
502 sl.lpTarget = lpBuffer;
503 sl.dwRemain = dwBufSize;
504 sl.dwTotalCopied = 0;
505  
506 const DWORD LEN = GetKeyLines(lpSection, NULL, 0);
507 if (LEN == 0)
508 return 0;
509  
510 LPTSTR psz = new TCHAR[LEN + 1];
511 GetKeyLines(lpSection, psz, LEN);
512 ParseDNTString(psz, __KeyPairProc, (LPVOID)(&sl));
513 delete [] psz;
514 if (lpBuffer != NULL)
515 lpBuffer[sl.dwTotalCopied] = _T('\0');
516 return sl.dwTotalCopied;
517 }
518  
519 // Get all section names from an ini file
520 DWORD CIni::GetSectionNames(LPTSTR lpBuffer, DWORD dwBufSize) const
521 {
522 if (lpBuffer == NULL)
523 {
524 // just calculate the required buffer size
525 DWORD dwLen = DEF_PROFILE_THRESHOLD;
526 LPTSTR psz = new TCHAR[dwLen + 1];
527 DWORD dwCopied = ::GetPrivateProfileSectionNames(psz, dwLen, m_pszPathName);
528 while (dwCopied + 2 >= dwLen)
529 {
530 dwLen += DEF_PROFILE_THRESHOLD;
531 delete [] psz;
532 psz = new TCHAR[dwLen + 1];
533 dwCopied = ::GetPrivateProfileSectionNames(psz, dwLen, m_pszPathName);
534 }
535  
536 delete [] psz;
537 return dwCopied + 2;
538 }
539 else
540 {
541 return ::GetPrivateProfileSectionNames(lpBuffer, dwBufSize, m_pszPathName);
542 }
543 }
544  
545 #ifdef __AFXWIN_H__
546 void CIni::GetSectionNames(CStringArray *pArray) const
547 {
548 if (pArray != NULL)
549 pArray->RemoveAll();
550  
551 const DWORD LEN = GetSectionNames(NULL, 0);
552 if (LEN == 0)
553 return;
554  
555 LPTSTR psz = new TCHAR[LEN + 1];
556 GetSectionNames(psz, LEN);
557 ParseDNTString(psz, __SubStrAdd, pArray);
558 delete [] psz;
559 }
560 #endif
561  
562 #ifdef __AFXWIN_H__
563 // Retrieve a list of key-lines(key-pairs) of the specified section
564 void CIni::GetKeyLines(LPCTSTR lpSection, CStringArray *pArray) const
565 {
566 if (pArray != NULL)
567 pArray->RemoveAll();
568  
569 const DWORD LEN = GetKeyLines(lpSection, NULL, 0);
570 if (LEN == 0)
571 return;
572  
573 LPTSTR psz = new TCHAR[LEN + 1];
574 GetKeyLines(lpSection, psz, LEN);
575 ParseDNTString(psz, __SubStrAdd, pArray);
576 delete [] psz;
577 }
578 #endif
579  
580 #ifdef __AFXWIN_H__
581 // Retrieve a list of key names of the specified section
582 void CIni::GetKeyNames(LPCTSTR lpSection, CStringArray *pArray) const
583 {
584 if (pArray == NULL)
585 return;
586  
587 pArray->RemoveAll();
588 #ifndef _VS_USED
589 const int LEN = GetKeyNames(lpSection, NULL, 0);
590 #else
591 const LEN = GetKeyNames(lpSection, NULL, 0);
592 #endif
593 LPTSTR psz = new TCHAR[LEN + 1];
594 GetKeyNames(lpSection, psz, LEN);
595 ParseDNTString(psz, __SubStrAdd, (LPVOID)pArray);
596 delete [] psz;
597 }
598 #endif
599  
600 // Remove whole section from the ini file
601 BOOL CIni::DeleteSection(LPCTSTR lpSection) const
602 {
603 return ::WritePrivateProfileString(lpSection, NULL, _T(""), m_pszPathName);
604 }
605  
606 // Remove a key from a section
607 BOOL CIni::DeleteKey(LPCTSTR lpSection, LPCTSTR lpKey) const
608 {
609 return ::WritePrivateProfileString(lpSection, lpKey, NULL, m_pszPathName);
610 }
611  
612 BOOL CIni::IsSectionExist(LPCTSTR lpSection) const
613 {
614 if (lpSection == NULL)
615 return FALSE;
616  
617 // first get the section name list, then check if lpSection exists
618 // in the list.
619 const DWORD LEN = GetSectionNames(NULL, 0);
620 if (LEN == 0)
621 return FALSE;
622  
623 LPTSTR psz = new TCHAR[LEN + 1];
624 GetSectionNames(psz, LEN);
625 BOOL RES = !ParseDNTString(psz, __SubStrCompare, (LPVOID)lpSection);
626 delete [] psz;
627 return RES;
628 }
629  
630 BOOL CIni::IsKeyExist(LPCTSTR lpSection, LPCTSTR lpKey) const
631 {
632 if (lpSection == NULL || lpKey == NULL)
633 return FALSE;
634  
635 // Test it with the default unique string
636 LPTSTR psz = __GetStringDynamic(lpSection, lpKey, DEF_PROFILE_TESTSTRING);
637 const BOOL RES = (_tcscmp(psz, DEF_PROFILE_TESTSTRING) != 0);
638 delete [] psz;
639 return RES;
640 }
641  
642 BOOL CIni::CopySection(LPCTSTR lpSrcSection, LPCTSTR lpDestSection, BOOL bFailIfExist) const
643 {
644 if (lpSrcSection == NULL || lpDestSection == NULL)
645 return FALSE;
646  
647 if (_tcsicmp(lpSrcSection, lpDestSection) == 0)
648 return FALSE;
649  
650 if (!IsSectionExist(lpSrcSection))
651 return FALSE;
652  
653 if (bFailIfExist && IsSectionExist(lpDestSection))
654 return FALSE;
655  
656 DeleteSection(lpDestSection);
657  
658 const DWORD SRC_LEN = GetKeyLines(lpSrcSection, NULL, 0);
659 LPTSTR psz = new TCHAR[SRC_LEN + 2];
660 //memset(psz, 0, sizeof(TCHAR) * (SRC_LEN + 2));
661 GetKeyLines(lpSrcSection, psz, SRC_LEN);
662 const BOOL RES = ::WritePrivateProfileSection(lpDestSection, psz, m_pszPathName);
663 delete [] psz;
664  
665 return RES;
666 }
667  
668 BOOL CIni::CopyKey(LPCTSTR lpSrcSection, LPCTSTR lpSrcKey, LPCTSTR lpDestSection, LPCTSTR lpDestKey, BOOL bFailIfExist) const
669 {
670 if (lpSrcSection == NULL || lpSrcKey == NULL || lpDestKey == NULL)
671 return FALSE;
672  
673 if (_tcsicmp(lpSrcSection, lpDestSection) == 0
674 && _tcsicmp(lpSrcKey, lpDestKey) == 0)
675 return FALSE;
676  
677 if (!IsKeyExist(lpSrcSection, lpSrcKey))
678 return FALSE;
679  
680 if (bFailIfExist && IsKeyExist(lpDestSection, lpDestKey))
681 return FALSE;
682  
683 LPTSTR psz = __GetStringDynamic(lpSrcSection, lpSrcKey);
684 const BOOL RES = WriteString(lpDestSection, lpDestKey, psz);
685 delete [] psz;
686 return RES;
687 }
688  
689 BOOL CIni::MoveSection(LPCTSTR lpSrcSection, LPCTSTR lpDestSection, BOOL bFailIfExist) const
690 {
691 return CopySection(lpSrcSection, lpDestSection, bFailIfExist)
692 && DeleteSection(lpSrcSection);
693 }
694  
695 BOOL CIni::MoveKey(LPCTSTR lpSrcSection, LPCTSTR lpSrcKey, LPCTSTR lpDestSection, LPCTSTR lpDestKey, BOOL bFailIfExist) const
696 {
697 return CopyKey(lpSrcSection, lpSrcKey, lpDestSection, lpDestKey, bFailIfExist)
698 && DeleteKey(lpSrcSection, lpSrcKey);
699 }
700  
701 /////////////////////////////////////////////////////////////////////////////////
702 // Helper Functions
703 /////////////////////////////////////////////////////////////////////////////////
704  
705 // Get a profile string value, return a heap pointer so we do not have to worry
706 // about the buffer size, however, this function requires the caller to manually
707 // free the memory.
708 // This function is the back-bone of all "Getxxx" functions of this class.
709 LPTSTR CIni::__GetStringDynamic(LPCTSTR lpSection, LPCTSTR lpKey, LPCTSTR lpDefault) const
710 {
711 TCHAR* psz = NULL;
712 if (lpSection == NULL || lpKey == NULL)
713 {
714 // Invalid section or key name, just return the default string
715 if (lpDefault == NULL)
716 {
717 // Empty string
718 psz = new TCHAR[1];
719 *psz = _T('\0');
720 }
721 else
722 {
723 psz = new TCHAR[_tcslen(lpDefault) + 1];
724 _tcscpy(psz, lpDefault);
725 }
726  
727 return psz;
728 }
729  
730 // Keep enlarging the buffer size until being certain on that the string we
731 // retrieved was original(not truncated).
732 DWORD dwLen = DEF_PROFILE_THRESHOLD;
733 psz = new TCHAR[dwLen + 1];
734 DWORD dwCopied = ::GetPrivateProfileString(lpSection, lpKey, lpDefault == NULL ? _T("") : lpDefault, psz, dwLen, m_pszPathName);
735 while (dwCopied + 1 >= dwLen)
736 {
737 dwLen += DEF_PROFILE_THRESHOLD;
738 delete [] psz;
739 psz = new TCHAR[dwLen + 1];
740 dwCopied = ::GetPrivateProfileString(lpSection, lpKey, lpDefault == NULL ? _T("") : lpDefault, psz, dwLen, m_pszPathName);
741 }
742  
743 return psz; // !!! Requires the caller to free this memory !!!
744 }
745  
746 // Split a string usinf a particular delimiter, split result are copied into lpBuffer
747 // in the "double null terminated string" format as the following figure shows:
748 // xxx\0xxxx\0xx\0xxx\0\0
749 //
750 // For example, if the delimiter is ",", then string "ab,cd,e" will be
751 // splitted into "ab\0cd\0e\0\0", this string format can be parsed into an array
752 // of sub strings easily using user defined functions or CIni::ParseStringArray.
753 DWORD CIni::__StringSplit(LPCTSTR lpString, LPTSTR lpBuffer, DWORD dwBufSize, LPCTSTR lpDelimiter, BOOL bTrimString)
754 {
755 if (lpString == NULL || lpBuffer == NULL || dwBufSize == 0)
756 return 0;
757  
758 DWORD dwCopied = 0;
759 *lpBuffer = _T('\0');
760 if (*lpString == _T('\0'))
761 return 0;
762  
763 // If lpDelimiter is NULL, use the default delimiter ",", if delimiter length
764 // is 0, then return whole string
765 if (lpDelimiter != NULL && *lpDelimiter == _T('\0'))
766 {
767 _tcsncpy(lpBuffer, lpString, dwBufSize - 1);
768 return _tcslen(lpBuffer);
769 }
770  
771 LPTSTR pszDel = (lpDelimiter == NULL) ? _tcsdup(DEF_PROFILE_DELIMITER) : _tcsdup(lpDelimiter);
772 const DWORD DEL_LEN = _tcslen(pszDel);
773 LPTSTR lpTarget = lpBuffer;
774  
775 // Search through lpString for delimiter matches, and extract sub strings out
776 LPCTSTR lpPos = lpString;
777 LPCTSTR lpEnd = _tcsstr(lpPos, pszDel);
778  
779 while (lpEnd != NULL)
780 {
781 LPTSTR pszSeg = __StrDupEx(lpPos, lpEnd);
782 if (bTrimString)
783 __TrimString(pszSeg);
784  
785 const DWORD SEG_LEN = _tcslen(pszSeg);
786 const DWORD COPY_LEN = min(SEG_LEN, dwBufSize - dwCopied);
787  
788 // Need to avoid buffer overflow
789 if (COPY_LEN > 0)
790 {
791 dwCopied += COPY_LEN + 1;
792 _tcsncpy(lpTarget, pszSeg, COPY_LEN);
793 lpTarget[COPY_LEN] = _T('\0');
794 lpTarget = &lpTarget[SEG_LEN + 1];
795 }
796 delete [] pszSeg;
797 lpPos = &lpEnd[DEL_LEN]; // Advance the pointer for next search
798 lpEnd = _tcsstr(lpPos, pszDel);
799 }
800  
801 // The last part of string, there may not be the trailing delimiter, so we
802 // need to take care of this part, too
803 LPTSTR pszSeg = _tcsdup(lpPos);
804 if (bTrimString)
805 __TrimString(pszSeg);
806  
807 const DWORD SEG_LEN = _tcslen(pszSeg);
808 const DWORD COPY_LEN = min(SEG_LEN, dwBufSize - dwCopied);
809  
810 if (COPY_LEN > 0)
811 {
812 dwCopied += COPY_LEN + 1;
813 _tcsncpy(lpTarget, pszSeg, COPY_LEN);
814 lpTarget[COPY_LEN] = _T('\0');
815 }
816  
817 delete [] pszSeg;
818 lpBuffer[dwCopied] = _T('\0');
819 delete [] pszDel;
820 return dwCopied;
821 }
822  
823 // Parse a "double null terminated string", pass each sub string to a user-defined
824 // callback function
825 BOOL CIni::ParseDNTString(LPCTSTR lpString, SUBSTRPROC lpFnStrProc, LPVOID lpParam)
826 {
827 if (lpString == NULL || lpFnStrProc == NULL)
828 return FALSE;
829  
830 LPCTSTR p = lpString;
831 DWORD dwLen = _tcslen(p);
832  
833 while (dwLen > 0)
834 {
835 if (!lpFnStrProc(p, lpParam))
836 return FALSE;
837  
838 p = &p[dwLen + 1];
839 dwLen = _tcslen(p);
840 }
841 return TRUE;
842 }
843  
844 // Callback function used to compare elements inside of a
845 // "double null terminated string" with a given string. Useful for
846 // searching in the section names list.
847 BOOL CALLBACK CIni::__SubStrCompare(LPCTSTR lpString1, LPVOID lpParam)
848 {
849 assert(lpString1 != NULL);
850 LPCTSTR lpString2 = (LPCTSTR)lpParam;
851 assert(lpString2 != NULL);
852 // if two string matches, return zero to stop the parsing
853 return _tcsicmp(lpString1, lpString2) != 0;
854 }
855  
856 // Callback function used to process a key-pair, it extracts the
857 // key name from the key-pair string
858 BOOL CALLBACK CIni:: __KeyPairProc(LPCTSTR lpString, LPVOID lpParam)
859 {
860 STR_LIMIT* psl = (STR_LIMIT*)lpParam;
861 if (lpString == NULL || psl== NULL)
862 return FALSE;
863  
864 LPCTSTR p = _tcschr(lpString, _T('='));
865 if (p == NULL || p == lpString)
866 return TRUE;
867  
868 // extract the sub-string on left side of the '='
869 LPTSTR psz = new TCHAR[_tcslen(lpString) + 1];
870  
2062 kakl 871 //#ifndef _VS6_USED
2061 mija 872 int i;
2062 kakl 873 //#endif
2061 mija 874  
875 for (int i = 0; &lpString[i] < p; i++)
876 psz[i] = lpString[i];
877 psz[i] = _T('\0');
878  
879 // trim
880 __TrimString(psz);
881 DWORD dwNameLen = _tcslen(psz);
882 DWORD dwCopyLen = 0;
883  
884 //copy to the buffer
885 if (psl->lpTarget != NULL)
886 {
887 dwCopyLen = (psl->dwRemain > 1) ? min(dwNameLen, psl->dwRemain - 1) : 0;
888 _tcsncpy(psl->lpTarget, psz, dwCopyLen);
889 psl->lpTarget[dwCopyLen] = _T('\0');
890 psl->lpTarget = &(psl->lpTarget[dwCopyLen + 1]);
891 psl->dwRemain -= dwCopyLen + 1;
892 }
893 else
894 {
895 dwCopyLen = dwNameLen;
896 }
897  
898 delete [] psz;
899 psl->dwTotalCopied += dwCopyLen + 1;
900 return TRUE;
901 }
902  
903 #ifdef __AFXWIN_H__
904 // Callback function used to add elements that are extracted from a
905 // "double null terminated string" to an MFC CStringArray.
906 BOOL CALLBACK CIni::__SubStrAdd(LPCTSTR lpString, LPVOID lpParam)
907 {
908 CStringArray* pArray = (CStringArray*)lpParam;
909 if (pArray == NULL || lpString == NULL)
910 return FALSE;
911  
912 pArray->Add(lpString);
913 return TRUE;
914 }
915 #endif
916  
917 // Convert an integer into binary string format
918 void CIni::__ToBinaryString(UINT nNumber, LPTSTR lpBuffer, DWORD dwBufSize)
919 {
920 if (dwBufSize == 0)
921 return;
922  
923 DWORD dwIndex = 0;
924 do
925 {
926 lpBuffer[dwIndex++] = (nNumber % 2) ? _T('1') : _T('0');
927 nNumber /= 2;
928 } while (nNumber > 0 && dwIndex < dwBufSize);
929  
930 lpBuffer[dwIndex] = _T('\0');
931 _tcsrev(lpBuffer);
932 }
933  
934 // Make sure the base will be expected value
935 int CIni::__ValidateBase(int nBase)
936 {
937 switch (nBase)
938 {
939 case BASE_BINARY:
940 case BASE_OCTAL:
941 case BASE_HEXADECIMAL:
942 break;
943  
944 default:
945 nBase = BASE_DECIMAL;
946 }
947  
948 return nBase;
949 }
950  
951 // Convert a signed integer into string representation, based on its base
952 void CIni::__IntToString(int nNumber, LPTSTR lpBuffer, int nBase)
953 {
954 switch (nBase)
955 {
956 case BASE_BINARY:
957 case BASE_OCTAL:
958 case BASE_HEXADECIMAL:
959 __UIntToString((UINT)nNumber, lpBuffer, nBase);
960 break;
961  
962 default:
963 _stprintf(lpBuffer, _T("%d"), nNumber);
964 break;
965 }
966 }
967  
968 // Convert an unsigned integer into string representation, based on its base
969 void CIni::__UIntToString(UINT nNumber, LPTSTR lpBuffer, int nBase)
970 {
971 switch (nBase)
972 {
973 case BASE_BINARY:
974 __ToBinaryString(nNumber, lpBuffer, DEF_PROFILE_NUM_LEN);
975 break;
976  
977 case BASE_OCTAL:
978 _stprintf(lpBuffer, _T("%o"), nNumber);
979 break;
980  
981 case BASE_HEXADECIMAL:
982 _stprintf(lpBuffer, _T("%X"), nNumber);
983 break;
984  
985 default:
986 _stprintf(lpBuffer, _T("%u"), nNumber);
987 break;
988 }
989 }
990  
991 BOOL CIni::StringToBool(LPCTSTR lpString, BOOL bDefault)
992 {
993 // Default: empty string
994 // TRUE: "true", "yes", non-zero decimal numner
995 // FALSE: all other cases
996 if (lpString == NULL || *lpString == _T('\0'))
997 return bDefault;
998  
999 return (_tcsicmp(lpString, _T("true")) == 0
1000 || _tcsicmp(lpString, _T("yes")) == 0
1001 || _tcstol(lpString, NULL, BASE_DECIMAL) != 0);
1002 }
1003  
1004 BOOL CIni::__TrimString(LPTSTR lpString)
1005 {
1006 if (lpString == NULL)
1007 return FALSE;
1008  
1009 BOOL bTrimmed = FALSE;
1010 int nLen = _tcslen(lpString);
1011  
1012 // '\n' and '\r' are actually not possible in this case, but anyway...
1013  
1014 // Trim right side
1015 while (nLen >= 0
1016 && (lpString[nLen - 1] == _T(' ')
1017 || lpString[nLen - 1] == _T('\t')
1018 || lpString[nLen - 1] == _T('\r')
1019 || lpString[nLen - 1] == _T('\n')))
1020 {
1021 lpString[--nLen] = _T('\0');
1022 bTrimmed = TRUE;
1023 }
1024  
1025 // Trim left side
1026 LPCTSTR p = lpString;
1027 while (*p == _T(' ')
1028 || *p == _T('\t')
1029 || *p == _T('\r')
1030 || *p == _T('\n'))
1031 {
1032 p = &p[1];
1033 bTrimmed = TRUE;
1034 }
1035  
1036 if (p != lpString)
1037 {
1038 LPTSTR psz = _tcsdup(p);
1039 _tcscpy(lpString, psz);
1040 delete [] psz;
1041 }
1042  
1043 return bTrimmed;
1044 }
1045  
1046 LPTSTR CIni::__StrDupEx(LPCTSTR lpStart, LPCTSTR lpEnd)
1047 {
1048 const DWORD LEN = ((DWORD)lpEnd - (DWORD)lpStart) / sizeof(TCHAR);
1049 LPTSTR psz = new TCHAR[LEN + 1];
1050 _tcsncpy(psz, lpStart, LEN);
1051 psz[LEN] = _T('\0');
1052 return psz; // !!! Requires the caller to free this memory !!!
1053 }
1054  
1055 /////////////////////////////////////////////////////////////////////////////////
1056 // End of Cini Class Implementation
1057 /////////////////////////////////////////////////////////////////////////////////
1058  
1059 // If you are getting this error:
1060 // ----------------------------------------------------------------------------
1061 // "fatal error C1010: unexpected end of file while looking for precompiled
1062 // header directive"
1063 //-----------------------------------------------------------------------------
1064 // Please scroll all the way up and uncomment '#include "stdafx.h"'