uLib  User mode C/C++ extended API library for Win32 programmers.
IniFile.cpp
Go to the documentation of this file.
1 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2 // Project: uLib - User mode library.
3 // Module: INI file support class. (Ini files are portable, registry is not.)
4 // Author: Copyright (c) Love Nystrom
5 // License: NNOSL (BSD descendant, see NNOSL.txt in the base directory).
6 //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7 
8 #include <uLib/IniFile.h>
9 #include <uLib/StrFunc.h>
10 #include <uLib/UtilFunc.h>
11 #include <uLib/Debug.h>
12 
13 // FIXME: IniFile should use ANSI strings only, not TCHAR.
14 
15 IniFile::IniFile( CSTR Name, UINT BufSize )
16 : _buffer(NULL), _bufSize(0), _valSize(0), UserData(0)
17 {
18  SetFilename( Name );
19  if (BufSize) AllocBuffer( BufSize );
20 }
21 
23 {
24  if (_buffer) mem_Free( _buffer );
25 }
26 
28 {
29  static CCSTR iniExt = _T(".ini");
30 
31  if (FName) _tcscpy_s( Filename, dimof(Filename), FName );
32  else
33  {
34  GetModuleFileName( NULL, Filename, dimof(Filename) );
35  TSTR dot = _tcsrchr( Filename, DOT );
37  if (dot) _tcscpy( dot, iniExt );
38  else _tcscat( Filename, iniExt );
40  }
41 }
42 
43 bool IniFile::AllocBuffer( UINT Size )
44 {
45  // Size 0 means: use default (MAX_PATH)
46 
47  bool ok = ((_bufSize >= Size) && (Size != 0));
48  if (!ok)
49  {
50  if (!Size) Size = MAX_PATH;
51  PBYTE newBuf = (PBYTE) mem_Alloc( Size );
52  ok = (newBuf != NULL);
53  if (ok)
54  {
55  if (_buffer) mem_Free( _buffer );
56  _buffer = newBuf;
57  _bufSize = Size;
58  }
59  }
60  if (_buffer) _buffer[0] = 0;
61  return ok;
62 }
63 
64 // READ -----------------------------------------------------------------------
65 
66 UINT IniFile::GetInt( CSTR Section, CSTR KeyName, INT Default )
67 {
68  return GetPrivateProfileInt( Section, KeyName, Default, Filename );
69 }
70 
71 INT IniFile::GetString( CSTR Section, CSTR KeyName, CSTR Default, TSTR Buf, UINT BufLen )
72 {
73  if (!_buffer) _valSize = 0;
74  else _valSize = GetPrivateProfileString( Section, KeyName, Default, (TSTR)_buffer, _bufSize, Filename ); // cache it
75 
76  if (_valSize) _tcsncpyz( Buf, (TSTR)_buffer, min_<UINT>( BufLen, (UINT)_valSize+1 ));
77  if (_valSize == INT(_bufSize-1) || _valSize == INT(_bufSize-2) ) // See MSDN
78  _valSize = -_valSize; // Insufficient buffer
79  return _valSize;
80 }
81 
82 TSTR IniFile::GetString( CSTR Section, CSTR KeyName, CSTR Default, INT* Size )
83 {
84  if (!_buffer) _valSize = 0;
85  else _valSize = GetPrivateProfileString( Section, KeyName, Default, (TSTR)_buffer, _bufSize, Filename );
86 
87  if (_valSize == INT(_bufSize-1) || _valSize == INT(_bufSize-2) )
88  _valSize = -_valSize; // Insufficient buffer
89  if (Size) *Size = _valSize;
90  return _valSize ? (TSTR)_buffer : NULL;
91 }
92 
93 //
94 
95 TSTR IniFile::GetSection( CSTR Section, INT* Size )
96 {
97  if (_buffer)
98  {
99  _valSize = GetPrivateProfileSection( Section, (TSTR)_buffer, _bufSize, Filename );
100  if (_valSize == INT(_bufSize - 2)) // If buffer was too small...
101  {
102  _buffer[_valSize] = _buffer[_valSize+1] = _NUL; // double-null term for safety.
103  _valSize = -_valSize;
104  }
105  if (Size) *Size = _valSize;
106  }
107  return (TSTR)_buffer;
108 }
109 
111 {
112  if (_buffer)
113  {
114  _valSize = GetPrivateProfileSectionNames( (TSTR)_buffer, _bufSize, Filename );
115  if (_valSize == INT(_bufSize - 2))
116  {
117  _buffer[_valSize] = _buffer[_valSize+1] = _NUL;
118  _valSize = -_valSize;
119  }
120  if (Size) *Size = _valSize;
121  }
122  return (TSTR)_buffer;
123 }
124 
125 PBYTE IniFile::GetStruct( CSTR Section, CSTR Key, UINT cbData )
126 {
127  BOOL ok = (_buffer != 0);
128  if (ok) ok = (_bufSize >= cbData+1 );
129  if (ok) ok = GetPrivateProfileStruct( Section, Key, _buffer, cbData, Filename );
130  return ok ? _buffer : NULL;
131 }
132 
133 static BYTE __hexVal( TCHAR Ch )
134 {
135  BYTE val;
136  if (Ch <= _T('9')) val = Ch - _T('0');
137  else val = 10 + (_totupper( Ch ) - _T('A'));
138  return val;
139 }
140 static BYTE _hexVal( TCHAR* Src )
141 {
142  BYTE hiVal = __hexVal( *Src );
143  BYTE loVal = __hexVal( *(Src+1) );
144  return (hiVal << 4) + loVal;
145 }
146 
147 PBYTE IniFile::GetBinary( CSTR Section, CSTR Key, INT* pSize )
148 {
149  INT size = 0;
150  GetString( Section, Key, NULL, &size );
151  if (size <= 0) return NULL;
152 
153  TSTR src = (TSTR)_buffer;
154  PBYTE dst = _buffer;
155  while( *src )
156  {
157  *dst = _hexVal( src );
158  src += 2;
159  dst++;
160  }
161  size /= 2;
162  size--;
163 
164  if (pSize) *pSize = size;
165 
166  BYTE csum = 0;
167  for( INT i=0; i < size; ++i ) csum += _buffer[i];
168  return (csum == _buffer[size]) ? _buffer : NULL;
169 }
170 
171 // WRITE ----------------------------------------------------------------------
172 
174 {
175  return WritePrivateProfileSection( Section, String, Filename );
176 }
177 
178 //static UINT multiSzSize( CSTR pmSz )
179 //{
180 // TSTR pEnd = (TSTR) pmSz;
181 // while( *pEnd ) pEnd = _tcschr( pEnd,0 ) + 1;
182 // return (pEnd - pmSz) + _TCHAR_SIZE; // Count the 2nd _NUL as well
183 //}
184 static UINT writeMultiSz( HANDLE hFile, CSTR pmSz )
185 {
186  UINT nStr = 0;
187  TSTR pEnd = (TSTR) pmSz;
188  while( pEnd && *pEnd )
189  {
190  TSTR pBegin = pEnd;
191  pEnd = _tcschr( pEnd, 0 );
192  if (pEnd)
193  {
194  WriteLine( hFile, pBegin );
195  nStr++;
196  pEnd++;
197  }
198  }
199  return nStr;
200 }
201 
203 {
204  // It seems WritePrivateProfileSection actually parses the multistring
205  // instead of just replacing the entire section with the given block :/
206  // So, here is one that just replaces the section verbatim.
207 
208  static const TCHAR _SqBrkt = _T('[');
209  static const TCHAR _ESqBrkt = _T(']');
210 
211  UINT nStr = 0, fpos;
212  HANDLE hFile = CheckHandle(
213  CreateFile( Filename, GENERIC_RW, 0, &DefSec, OPEN_ALWAYS, 0, NULL )
214  );
215  if (!hFile)
216  DPrint( DP_ERROR, _F("Can't open %s: %s\n"), Filename, SysErrorMsg() );
217  else
218  {
219  TSTR pSect = NULL, pNext = NULL;
220  UINT nlen = (UINT)_tcslen( Section ); // Section name length
221  PBYTE fbuf = NULL;
222  UINT fsize = GetFileSize( hFile, NULL );
223  if (fsize)
224  {
225  fbuf = (PBYTE) mem_Alloc( fsize );
226  if (!fbuf)
227  {
228  DPrint( DP_ERROR, _F("Out of memory (fsize=%lu).\n"), fsize );
229  goto wrs_Close;
230  }
231  if (BlockRead( hFile, fbuf, fsize ) == fsize)
232  {
233  // Find Section so it can be replaced.
234  // If not found (pSect=NULL), it will be appended instead.
235 
236  TSTR pTmp = (TSTR) fbuf;
237  while( pTmp )
238  {
239  pTmp = _tcschr( pTmp, _SqBrkt );
240  if (pTmp)
241  {
242  if (_tcsnicmp( &pTmp[1], Section, nlen ) == 0)
243  {
244  // Check if it's a partial or full Section name match
245  TSTR pEnd = pTmp + (nlen+1);
246  if (*pEnd == _ESqBrkt) // ']' - Found it
247  {
248  pSect = pTmp; // '['
249  pNext = _tcschr( pEnd, _SqBrkt ); // Next section, if any
250  break;
251  }
252  }
253  pTmp++;
254  }
255  }
256  }
257  }
258 
259  // Write out MultiSz, either at old pos, or appended at end of file.
260  // This code is outside the BlockRead compound so it can be written
261  // to a file with no previous content.
262 
263  fpos = pSect ? UINT( PBYTE(pSect) - fbuf ) : fsize;
264  SetFilePointer( hFile, fpos, NULL, FILE_BEGIN );
265 
266  WriteStr( hFile, _T("[%s]\r\n"), Section ); // Section heading (rewrite).
267  nStr = writeMultiSz( hFile, MultiSz ); // Section data.
268 
269  if (pNext) // Any more sections trailing ?
270  {
271  BlockWrite( hFile, (PVOID)_T("\r\n"), 2*sizeof(TCHAR) ); // Add blank line.
272  UINT nbytes = fsize - UINT( PBYTE(pNext) - fbuf ); // Nr of bytes after pNext.
273  BlockWrite( hFile, pNext, nbytes ); // Write out trailing sections.
274  }
275  mem_Free( fbuf );
276 
277  wrs_Close:
278  CloseHandle( hFile );
279  }
280  return nStr;
281 }
282 
283 BOOL IniFile::WriteInt( CSTR Section, CSTR KeyName, LONG Value, BYTE Radix )
284 {
285  CSTR fmt;
286  switch( Radix ) // GetPrivateProfileInt can handle radix 10 and 16.
287  {
288  case 10: fmt = _T("%li"); break;
289  case 16: fmt = _T("0x%08X"); break;
290  default: return FALSE;
291  }
292  return WriteStringFmt( Section, KeyName, fmt, Value );
293 }
294 
295 BOOL IniFile::WriteString( CSTR Section, CSTR KeyName, CSTR Text )
296 {
297  return WritePrivateProfileString( Section, KeyName, TSTR(Text), Filename );
298 }
299 
300 BOOL IniFile::WriteStringFmt( CSTR Section, CSTR KeyName, CSTR Fmt, ... )
301 {
302  va_list va;
303 
304  va_start( va, Fmt );
305  size_t dim = _bufSize/sizeof(TCHAR); // Buffer dimension (TCHAR count)
306  _vstprintf_s( (TSTR)_buffer, dim, Fmt, va );
307  va_end( va );
308 
309  return WritePrivateProfileString( Section, KeyName, (TSTR)_buffer, Filename );
310  UNUSED( dim ); // if __GNUC__
311 }
312 
313 BOOL IniFile::WriteStruct( CSTR Section, CSTR Key, PVOID pStruct, UINT Size )
314 {
315  return WritePrivateProfileStruct( Section, Key, pStruct, Size, Filename );
316 }
317 
318 BOOL IniFile::DeleteString( CSTR Section, CSTR KeyName )
319 {
320  return WritePrivateProfileString( Section, KeyName, NULL, Filename );
321 }
322 
324 {
325  return WritePrivateProfileString( Section, NULL, NULL, Filename );
326 }
327 
328 // Common chores..
329 
330 BOOL IniFile::SaveWndRect( HWND hWnd, CSTR Section, CSTR Key )
331 {
332  BOOL ok = IsWindow( hWnd );
333  if ( ok )
334  {
335  RECT r; ok = GetWindowRect( hWnd, &r );
336  if (ok) ok = WriteStruct( Section, Key, &r, sizeof(RECT) );
337 
338  }
339  return ok;
340 }
341 
342 BOOL IniFile::RestoreWndRect( HWND hWnd, CSTR Section, CSTR Key )
343 {
344  BOOL ok = IsWindow( hWnd );
345  if ( ok )
346  {
347  PRECT pr = (PRECT) GetStruct( Section, Key, sizeof(RECT) );
348  ok = (pr != NULL);
349  if ( ok )
350  {
351  // Constrain rect to stay on the visible screen.
352  SIZE scrSiz = { SYSMET( CXSCREEN ), SYSMET( CYSCREEN ) };
353  if ((pr->left < 0) || (pr->left > scrSiz.cx)) OffsetRect( pr, -pr->left, 0 );
354  if ((pr->top < 0) || (pr->top > scrSiz.cy)) OffsetRect( pr, 0, -pr->top );
355 
356  AbsToDimRect( pr );
357  ok = SetWindowPos( hWnd, NULL, pr->left, pr->top, pr->right, pr->bottom, SWP_NOZORDER );
358  }
359  }
360  return ok;
361 }
362 
363 // EOF
UINT BufSize()
Definition: IniFile.h:53
#define DOT
Definition: Common.h:1216
TCHAR Filename[MAX_PATH]
Definition: IniFile.h:37
HANDLE CheckHandle(HANDLE Hnd)
Definition: KernelUtil.cpp:75
void SetFilename(CSTR FName)
Definition: IniFile.cpp:27
#define SYSMET(Id)
Definition: UtilFunc.h:923
#define CSTR
Definition: Common.h:329
BOOL WriteStringFmt(CSTR Section, CSTR KeyName, CSTR Fmt,...)
Definition: IniFile.cpp:300
PBYTE GetBinary(CSTR Section, CSTR Key, OUT INT *pSize)
Definition: IniFile.cpp:147
void * mem_Alloc(size_t Bytes)
Definition: MemFunc.cpp:33
PBYTE GetStruct(CSTR Section, CSTR Key, UINT cbStruct)
Definition: IniFile.cpp:125
#define BEGIN_STRSAFE_OVERRIDE
Definition: StrFunc.h:28
#define TSTR
Definition: Common.h:328
unsigned char * PBYTE
Definition: Common.h:412
UINT BlockWrite(HANDLE hFile, PVOID Buf, UINT nBytes)
Definition: IoUtil.cpp:423
BOOL WriteLine(HANDLE hFile, CSTR Buf, UINT ccBuf=0)
Definition: IoUtil.cpp:432
#define dimof(x)
Definition: Common.h:949
BOOL SaveWndRect(HWND hWnd, CSTR Section, CSTR Key)
Definition: IniFile.cpp:330
void __cdecl DPrint(int Level, CSTR Fmt,...)
Definition: Debug.cpp:134
#define _NUL
Definition: Common.h:1246
TSTR GetSectionNames(OPTOUT INT *Size=NULL)
Definition: IniFile.cpp:110
INT GetString(CSTR Section, CSTR KeyName, CSTR Default, TSTR Buf, UINT BufLen)
Definition: IniFile.cpp:71
#define WriteStr
Definition: UtilFunc.h:2459
BOOL(WINAPI *SysImgList::Shell_GetImageLists)(HIMAGELIST *pimlLarge
const LPCTSTR CCSTR
Definition: Common.h:335
void * mem_Free(void *pBlk)
Definition: MemFunc.cpp:124
BOOL WriteString(CSTR Section, CSTR KeyName, CSTR Text)
Definition: IniFile.cpp:295
BOOL WriteSection(CSTR Section, CSTR Strings)
Definition: IniFile.cpp:173
CSTR SysErrorMsg(DWORD Err=0, TSTR Buf=NULL, UINT Length=0)
Definition: Debug.cpp:39
BOOL DeleteSection(CSTR Section)
Definition: IniFile.cpp:323
#define GENERIC_RW
Definition: Common.h:1128
SECURITY_ATTRIBUTES DefSec
Definition: Common.cpp:20
#define DP_ERROR
Definition: Debug.h:82
BOOL DeleteString(CSTR Section, CSTR KeyName)
Definition: IniFile.cpp:318
UINT BlockRead(HANDLE hFile, PVOID Buf, UINT nBytes)
Definition: IoUtil.cpp:417
#define UNUSED(x)
Definition: Common.h:970
Debug and error handling support.
UINT GetInt(CSTR Section, CSTR KeyName, INT Default)
Definition: IniFile.cpp:66
IniFile(CSTR FName=NULL, UINT BufSize=4096)
Definition: IniFile.cpp:15
virtual ~IniFile()
Definition: IniFile.cpp:22
BOOL WriteInt(CSTR Section, CSTR KeyName, LONG Value, BYTE Radix=10)
Definition: IniFile.cpp:283
bool AllocBuffer(UINT Size)
Definition: IniFile.cpp:43
BOOL WriteStruct(CSTR Section, CSTR Key, PVOID pStruct, UINT Size)
Definition: IniFile.cpp:313
#define _F(s)
Definition: Debug.h:49
BOOL RestoreWndRect(HWND hWnd, CSTR Section, CSTR Key)
Definition: IniFile.cpp:342
LPRECT AbsToDimRect(LPRECT pRect)
Definition: UtilFunc.cpp:86
BOOL WriteRawSection(CSTR Section, CSTR MultiSz)
Definition: IniFile.cpp:202
#define END_STRSAFE_OVERRIDE
Definition: StrFunc.h:29
TSTR GetSection(CSTR Section, OPTOUT INT *Size=NULL)
Definition: IniFile.cpp:95
unsigned char BYTE
Definition: Common.h:412
#define _tcsncpyz
Definition: StrFunc.h:77