source: branches/branch-1-0/src/helpers/xprf.c@ 472

Last change on this file since 472 was 451, checked in by pr, 4 years ago

Add offset limit checking.

  • Property svn:eol-style set to CRLF
  • Property svn:keywords set to Author Date Id Revision
File size: 41.4 KB
Line 
1
2/*
3 *@@sourcefile xprf.c:
4 * contains replacement profile (INI) functions.
5 * This file is new with V0.9.5 (2000-08-10) [umoeller].
6 *
7 * These functions are quite similar to the regular Prf*
8 * APIs, with the following advantages:
9 *
10 * -- They do not use shared memory, but the default
11 * memory allocation functions (malloc() etc.).
12 * This greatly reduces the pressure on the process's
13 * address space which apparently the default Prf*
14 * functions are causing with large INI files.
15 *
16 * -- Profiles are written out to disk in one flush, not
17 * in the 32 KB chunks that the regular Prf* functions
18 * use.
19 *
20 * Other differences:
21 *
22 * -- They cannot be used interchangably. Once you open
23 * a profile using xprfOpenProfile, you must use the
24 * extended functions.
25 *
26 * -- The INI file is kept open after xprfOpenProfile
27 * until xprfCloseProfile is called. Besides, we use
28 * DosProtectOpen so that a second open of the same INI
29 * file will always fail until xprfCloseProfile is called
30 * (sorta like a mutex for profiles).
31 * This is independent of the process or thread which
32 * is doing the second open.
33 *
34 * This is because since we are not using shared memory,
35 * some other sort of protection had to be introduced
36 * to make sure no two processes operate on the same INI.
37 *
38 * Still, these functions are NOT thread-safe for the same profile.
39 * If you open the profile on one thread and write and read
40 * concurrently on two threads, there's no protection, and everything
41 * will blow up. The functions are reentrant though, so for different
42 * profiles there will be no problems.
43 *
44 * -- All changes to the INI files using xprfWriteProfileData
45 * are only made to the file in memory. Only xprfCloseProfile
46 * will flush the changes to disk. (I am not sure how the
47 * default PrfCloseProfile handles this on files other than
48 * HINI_USER and HINI_SYSTEM.)
49 *
50 * -- HINI_USER and HINI_SYSTEM don't work. To retrieve data
51 * from them, use the standard Prf* functions. You can however
52 * use the new functions to create a duplicate of these files.
53 *
54 * -- One similarity: All data items are limited to 64K,
55 * as with the standard profiles. This is not a limitation
56 * of the code, but of the INI file format, which uses
57 * USHORT's for all item length specifications.
58 *
59 * Thanks go out to Carsten Arnold for sending the INI file
60 * format information (xprf.h) to me, which enabled me to
61 * create this in the first place.
62 *
63 * Usage: All OS/2 programs.
64 *
65 * Function prefixes:
66 * -- xprf* replacement profile (INI) functions
67 *
68 * Note: Version numbering in this file relates to XWorkplace version
69 * numbering.
70 *
71 *@@header "helpers\xprf.h"
72 *@@added V0.9.5 (2000-08-10) [umoeller]
73 */
74
75/*
76 * Copyright (C) 2000-2021 Ulrich M”ller.
77 * This file is part of the "XWorkplace helpers" source package.
78 * This is free software; you can redistribute it and/or modify
79 * it under the terms of the GNU General Public License as published
80 * by the Free Software Foundation, in version 2 as it comes in the
81 * "COPYING" file of the XWorkplace main distribution.
82 * This program is distributed in the hope that it will be useful,
83 * but WITHOUT ANY WARRANTY; without even the implied warranty of
84 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
85 * GNU General Public License for more details.
86 */
87
88#define OS2EMX_PLAIN_CHAR
89 // this is needed for "os2emx.h"; if this is defined,
90 // emx will define PSZ as _signed_ char, otherwise
91 // as unsigned char
92
93#define INCL_DOSERRORS
94#define INCL_WINSHELLDATA
95#include <os2.h>
96
97#include <stdlib.h>
98#include <stdio.h>
99#include <string.h>
100
101#include "setup.h" // code generation and debugging options
102
103#include "helpers\linklist.h"
104#include "helpers\prfh.h"
105#include "helpers\xprf.h"
106
107#pragma hdrstop
108
109/*
110 *@@category: Helpers\Profile (INI) replacement functions
111 * See xprf.c.
112 */
113
114/* ******************************************************************
115 *
116 * Declarations
117 *
118 ********************************************************************/
119
120/*
121 *@@ XINIAPPDATA:
122 * application structure in XINI.
123 */
124
125typedef struct _XINIAPPDATA
126{
127 PSZ pszAppName;
128 LINKLIST llKeys; // contains PXINIKEYDATA pointers
129 ULONG cKeys; // count of items on list
130} XINIAPPDATA, *PXINIAPPDATA;
131
132/*
133 *@@ XINIKEYDATA:
134 * key/data structure in XINIAPPDATA.
135 */
136
137typedef struct _XINIKEYDATA
138{
139 PSZ pszKeyName;
140 PBYTE pbData;
141 ULONG cbData;
142} XINIKEYDATA, *PXINIKEYDATA;
143
144/* ******************************************************************
145 *
146 * Helpers
147 *
148 ********************************************************************/
149
150/*
151 * FindApp:
152 * attempts to find the specified application
153 * in the given profile data.
154 * Returns NULL if not found.
155 *
156 * Private helper.
157 *
158 *@@changed V1.0.0 (2002-09-17) [umoeller]: now returning APIRET
159 */
160
161STATIC APIRET FindApp(PXINI pXIni, // in: profile opened with xprfOpenProfile
162 const char *pcszApp,
163 PXINIAPPDATA *ppAppData)
164{
165 PLISTNODE pAppNode = lstQueryFirstNode(&pXIni->llApps);
166 while (pAppNode)
167 {
168 PXINIAPPDATA pAppDataThis = (PXINIAPPDATA)pAppNode->pItemData;
169 if (!strcmp(pAppDataThis->pszAppName, pcszApp))
170 {
171 *ppAppData = pAppDataThis;
172 return NO_ERROR;
173 }
174
175 pAppNode = pAppNode->pNext;
176 }
177
178 return PRFERR_INVALID_APP_NAME;
179}
180
181/*
182 * CreateApp:
183 * creates a new application in the specified
184 * profile structure and appends it to the list.
185 * This does NOT check for whether the app is
186 * already in the profile.
187 *
188 * Private helper.
189 *
190 *@@changed V1.0.0 (2002-09-17) [umoeller]: now returning APIRET
191 */
192
193STATIC APIRET CreateApp(PXINI pXIni, // in: profile opened with xprfOpenProfile
194 const char *pcszApp,
195 PXINIAPPDATA *ppAppData)
196{
197 PXINIAPPDATA pAppData;
198 if (pAppData = (PXINIAPPDATA)malloc(sizeof(XINIAPPDATA)))
199 {
200 pAppData->pszAppName = strdup(pcszApp);
201 lstInit(&pAppData->llKeys, FALSE);
202 pAppData->cKeys = 0;
203
204 // store in INI's apps list
205 lstAppendItem(&pXIni->llApps, pAppData);
206
207 *ppAppData = pAppData;
208 return NO_ERROR;
209 }
210
211 return ERROR_NOT_ENOUGH_MEMORY;
212}
213
214/*
215 * FindKey:
216 * attempts to find the specified key
217 * in the given application.
218 * Returns NULL if not found.
219 *
220 * Private helper.
221 *
222 *@@changed V1.0.0 (2002-09-17) [umoeller]: now returning APIRET
223 */
224
225STATIC APIRET FindKey(PXINIAPPDATA pAppData,
226 const char *pcszKey,
227 PXINIKEYDATA *ppKeyData)
228{
229 PLISTNODE pKeyNode = lstQueryFirstNode(&pAppData->llKeys);
230 while (pKeyNode)
231 {
232 PXINIKEYDATA pKeyDataThis = (PXINIKEYDATA)pKeyNode->pItemData;
233 if (!strcmp(pKeyDataThis->pszKeyName, pcszKey))
234 {
235 *ppKeyData = pKeyDataThis;
236 return NO_ERROR;
237 }
238
239 pKeyNode = pKeyNode->pNext;
240 }
241
242 return PRFERR_INVALID_KEY_NAME;
243}
244
245/*
246 * CreateKey:
247 * creates a new key in the specified application
248 * structure and appends it to the list.
249 * This does NOT check for whether the key is
250 * already in the application.
251 *
252 * Private helper.
253 *
254 *@@changed V1.0.0 (2002-09-17) [umoeller]: now returning APIRET
255 */
256
257STATIC APIRET CreateKey(PXINIAPPDATA pAppData,
258 const char *pcszKey, // in: key name
259 PBYTE pbData, // in: data for key
260 ULONG cbData, // in: sizeof (*pbData)
261 PXINIKEYDATA *ppKeyData) // out: new key data
262{
263 PXINIKEYDATA pKeyData;
264 if (pKeyData = (PXINIKEYDATA)malloc(sizeof(XINIKEYDATA)))
265 {
266 pKeyData->pszKeyName = strdup(pcszKey);
267
268 if (pKeyData->pbData = (PBYTE)malloc(cbData))
269 {
270 memcpy(pKeyData->pbData, pbData, cbData);
271 pKeyData->cbData = cbData;
272 // store in app's keys list
273 lstAppendItem(&pAppData->llKeys, pKeyData);
274 pAppData->cKeys++;
275
276 *ppKeyData = pKeyData;
277 return NO_ERROR;
278 }
279 else
280 // malloc failed:
281 free(pKeyData);
282 }
283
284 return ERROR_NOT_ENOUGH_MEMORY;
285}
286
287/*
288 * FreeKey:
289 * frees the specified key. Does not remove
290 * the key from the keys list in XINIAPPDATA
291 * however.
292 *
293 * Private helper.
294 */
295
296STATIC VOID FreeKey(PXINIKEYDATA pKeyDataThis)
297{
298 if (pKeyDataThis->pszKeyName)
299 free(pKeyDataThis->pszKeyName);
300 if (pKeyDataThis->pbData)
301 free(pKeyDataThis->pbData);
302 free(pKeyDataThis);
303}
304
305/*
306 *@@ FreeKeyIfExists:
307 *
308 *@@added V1.0.0 (2002-09-17) [umoeller]
309 */
310
311STATIC VOID FreeKeyIfExists(PXINI pXIni, // in: profile opened with xprfOpenProfile
312 PXINIAPPDATA pAppData,
313 PCSZ pcszKey)
314{
315 // find key
316 PXINIKEYDATA pKeyData;
317
318 if (!FindKey(pAppData,
319 pcszKey,
320 &pKeyData))
321 {
322 // key exists: kill that
323 FreeKey(pKeyData);
324 // and remove from app's keys list
325 lstRemoveItem(&pAppData->llKeys, pKeyData);
326 pAppData->cKeys--;
327
328 // rewrite profile on close
329 pXIni->fDirty = TRUE;
330 }
331 // else key doesn't exist:
332 // nothing to do
333}
334
335/*
336 * FreeApp:
337 * frees the specified application. Does not remove
338 * the application from the application list in XINI
339 * however.
340 *
341 * Private helper.
342 */
343
344STATIC VOID FreeApp(PXINIAPPDATA pAppDataThis)
345{
346 PLISTNODE pKeyNode = lstQueryFirstNode(&pAppDataThis->llKeys);
347 while (pKeyNode)
348 {
349 PXINIKEYDATA pKeyDataThis = (PXINIKEYDATA)pKeyNode->pItemData;
350
351 FreeKey(pKeyDataThis);
352
353 pKeyNode = pKeyNode->pNext;
354 }
355
356 if (pAppDataThis->pszAppName)
357 free(pAppDataThis->pszAppName);
358
359 lstClear(&pAppDataThis->llKeys);
360
361 free(pAppDataThis);
362}
363
364/*
365 * FreeINI:
366 * cleans up the specified ini structure entirely.
367 *
368 * Private helper.
369 */
370
371STATIC VOID FreeINI(PXINI pXIni) // in: profile opened with xprfOpenProfile
372{
373 if (pXIni)
374 {
375 PLISTNODE pAppNode = lstQueryFirstNode(&pXIni->llApps);
376 while (pAppNode)
377 {
378 PXINIAPPDATA pAppDataThis = (PXINIAPPDATA)pAppNode->pItemData;
379
380 FreeApp(pAppDataThis);
381
382 pAppNode = pAppNode->pNext;
383 }
384
385 lstClear(&pXIni->llApps);
386 free(pXIni);
387 }
388}
389
390/* ******************************************************************
391 *
392 * Read/write data
393 *
394 ********************************************************************/
395
396/*
397 * ReadINI:
398 * reads in the entire INI file from disk and
399 * initializes all internal data structures.
400 *
401 * Private helper.
402 *
403 *@@changed V1.0.0 (2002-09-17) [umoeller]: now returning APIRET
404 *@@changed WarpIN V1.0.25 (2021-07-04) [pr]: add limit checking
405 */
406
407STATIC APIRET ReadINI(PXINI pXIni) // in: profile opened with xprfOpenProfile
408{
409 APIRET arc;
410 FILESTATUS3 fs3;
411
412 if (!(arc = DosQueryFileInfo(pXIni->hFile,
413 FIL_STANDARD,
414 &fs3,
415 sizeof(fs3))))
416 {
417 PBYTE pbFileData;
418 if (!(pbFileData = (PBYTE)malloc(fs3.cbFile)))
419 arc = ERROR_NOT_ENOUGH_MEMORY;
420 else
421 {
422 ULONG ulSet = 0;
423
424 if (!(arc = DosSetFilePtr(pXIni->hFile,
425 0,
426 FILE_BEGIN,
427 &ulSet)))
428 {
429 ULONG cbRead = 0;
430 if (!(arc = DosRead(pXIni->hFile,
431 pbFileData,
432 fs3.cbFile,
433 &cbRead)))
434 {
435 if (cbRead != fs3.cbFile || cbRead < sizeof(INIFILE_HEADER))
436 arc = ERROR_NO_DATA;
437 else
438 {
439 PINIFILE_HEADER pHeader = (PINIFILE_HEADER)pbFileData;
440 if (pHeader->magic == 0xFFFFFFFF)
441 {
442 ULONG ulAppOfs = pHeader->offFirstApp;
443
444 // create-applications loop
445 while ((ulAppOfs) && (ulAppOfs + sizeof(INIFILE_APP) <= cbRead) && (!arc))
446 {
447 // application struct
448 PINIFILE_APP pApp = (PINIFILE_APP)(pbFileData + ulAppOfs);
449 ULONG ulKeysOfs = pApp->offFirstKeyInApp;
450 PXINIAPPDATA pIniApp;
451
452 if (arc = CreateApp(pXIni,
453 (PBYTE)(pbFileData + pApp->offAppName),
454 &pIniApp))
455 break;
456
457 // create-keys loop
458 while ((ulKeysOfs) && (ulKeysOfs + sizeof(INIFILE_KEY) <= cbRead) && (!arc))
459 {
460 PINIFILE_KEY pKey = (PINIFILE_KEY)(pbFileData + ulKeysOfs);
461
462 PXINIKEYDATA pIniKey;
463
464 if (arc = CreateKey(pIniApp,
465 (PSZ)(pbFileData + pKey->offKeyName),
466 (PBYTE)(pbFileData + pKey->offKeyData),
467 pKey->lenKeyData,
468 &pIniKey))
469 break;
470
471 // next key; can be null
472 ulKeysOfs = pKey->offNextKeyInApp;
473 }
474
475 // next application; can be null
476 ulAppOfs = pApp->offNextApp;
477 }
478 }
479 }
480 }
481 }
482
483 free(pbFileData);
484 }
485 }
486
487 return arc;
488}
489
490/*
491 * WriteINI:
492 * writes the entire data structure back to disk.
493 * Does not close the file.
494 *
495 * Private helper.
496 *
497 *@@changed V1.0.0 (2002-09-17) [umoeller]: now returning APIRET
498 */
499
500STATIC APIRET WriteINI(PXINI pXIni) // in: profile opened with xprfOpenProfile
501{
502 APIRET arc = NO_ERROR;
503 ULONG ulTotalFileSize = sizeof(INIFILE_HEADER);
504 ULONG ulSet = 0;
505 PBYTE pbData2Write = NULL;
506
507 // check how much memory we'll need:
508 // one INIFILE_HEADER
509 // + for each app: one INIFILE_APP plus app name length
510 // + for each key: one INIFILE_KEY plus key name length plus data length
511
512 // go thru all apps
513 PLISTNODE pAppNode = lstQueryFirstNode(&pXIni->llApps);
514
515 while (pAppNode)
516 {
517 PLISTNODE pKeyNode;
518
519 PXINIAPPDATA pAppDataThis = (PXINIAPPDATA)pAppNode->pItemData;
520
521 // one INIFILE_APP plus app name length for each app
522 ulTotalFileSize += sizeof(INIFILE_APP)
523 + strlen(pAppDataThis->pszAppName)
524 + 1; // null terminator
525
526 // for each app, go thru all keys
527 pKeyNode = lstQueryFirstNode(&pAppDataThis->llKeys);
528 while (pKeyNode)
529 {
530 PXINIKEYDATA pKeyDataThis = (PXINIKEYDATA)pKeyNode->pItemData;
531 ulTotalFileSize += sizeof(INIFILE_KEY)
532 + strlen(pKeyDataThis->pszKeyName)
533 + pKeyDataThis->cbData
534 + 1; // null terminator
535
536 pKeyNode = pKeyNode->pNext;
537 }
538
539 pAppNode = pAppNode->pNext;
540 }
541
542 // allocate buffer for total size
543 if (pbData2Write = (PBYTE)malloc(ulTotalFileSize))
544 {
545 // set header in buffer
546 PINIFILE_HEADER pHeader = (PINIFILE_HEADER)pbData2Write;
547 // pointer into buffer for current write
548 // (used below)
549 ULONG ulCurOfs = sizeof(INIFILE_HEADER);
550
551 // 1) set up header
552
553 pHeader->magic = 0xFFFFFFFF;
554 if (lstCountItems(&pXIni->llApps))
555 // we have any applications:
556 pHeader->offFirstApp = sizeof(INIFILE_HEADER);
557 // offset of first application in file
558 else
559 // empty INI file:
560 pHeader->offFirstApp = 0;
561 pHeader->lenFile = ulTotalFileSize;
562 pHeader->filler1 = 0;
563 pHeader->filler2 = 0;
564
565 // 2) for-all-applications loop
566
567 pAppNode = lstQueryFirstNode(&pXIni->llApps);
568 while (pAppNode)
569 {
570 PXINIAPPDATA pAppDataThis = (PXINIAPPDATA)pAppNode->pItemData;
571 ULONG cbAppName = strlen(pAppDataThis->pszAppName) + 1;
572
573 // layout of application entry in file:
574 // -- struct PINIFILE_APP (ulCurOfs right now)
575 // -- application name (null-terminated)
576 // -- INIFILE_KEY 1
577 // -- INIFILE_KEY 2 ...
578 // -- next struct PINIFILE_APP
579
580 // make pointer to application entry
581 PINIFILE_APP pIniAppCurrent = (PINIFILE_APP)(pbData2Write + ulCurOfs);
582
583 // write out application entry
584 // pIniAppCurrent->offNextApp = 0;
585 // pIniAppCurrent->offFirstKeyInApp = ulCurOfs + cbAppName;
586 pIniAppCurrent->filler1 = 0;
587 pIniAppCurrent->lenAppName
588 = pIniAppCurrent->_lenAppName
589 = cbAppName;
590 // set offset to application name: put this right after the application
591 ulCurOfs += sizeof(INIFILE_APP);
592 pIniAppCurrent->offAppName = ulCurOfs;
593
594 // write app name (null-terminated)
595 memcpy(pbData2Write + ulCurOfs,
596 pAppDataThis->pszAppName,
597 cbAppName);
598 ulCurOfs += cbAppName;
599
600 // ulCurOfs points to INIFILE_KEY entry now
601 if (pAppDataThis->cKeys)
602 {
603 // we have keys:
604 PLISTNODE pKeyNode = lstQueryFirstNode(&pAppDataThis->llKeys);
605 pIniAppCurrent->offFirstKeyInApp = ulCurOfs;
606
607 // 3) for-all-keys loop per application
608
609 while (pKeyNode)
610 {
611 PXINIKEYDATA pKeyDataThis = (PXINIKEYDATA)pKeyNode->pItemData;
612 ULONG cbKeyName = strlen(pKeyDataThis->pszKeyName) + 1;
613
614 PINIFILE_KEY pIniKeyCurrent = (PINIFILE_KEY)(pbData2Write + ulCurOfs);
615 pIniKeyCurrent->filler1 = 0;
616 ulCurOfs += sizeof(INIFILE_KEY);
617 // has offset to key name now
618
619 // a) key name
620 pIniKeyCurrent->lenKeyName
621 = pIniKeyCurrent->_lenKeyName
622 = cbKeyName;
623 pIniKeyCurrent->offKeyName = ulCurOfs;
624 memcpy(pbData2Write + ulCurOfs,
625 pKeyDataThis->pszKeyName,
626 cbKeyName);
627 ulCurOfs += cbKeyName;
628 // has offset to data now
629
630 // b) data
631 pIniKeyCurrent->lenKeyData
632 = pIniKeyCurrent->_lenKeyData
633 = pKeyDataThis->cbData;
634 pIniKeyCurrent->offKeyData = ulCurOfs;
635 memcpy(pbData2Write + ulCurOfs,
636 pKeyDataThis->pbData,
637 pKeyDataThis->cbData);
638 ulCurOfs += pKeyDataThis->cbData;
639 // points to after all key data now;
640 // this receives either the next key/data block
641 // or the next application or nothing
642
643 // ofs of next key:
644 if (pKeyNode->pNext)
645 pIniKeyCurrent->offNextKeyInApp = ulCurOfs;
646 else
647 // last key:
648 pIniKeyCurrent->offNextKeyInApp = 0;
649
650 pKeyNode = pKeyNode->pNext;
651 }
652
653 // ulCurOfs points to after the last keys entry now
654 }
655 else
656 // no keys:
657 pIniAppCurrent->offFirstKeyInApp = 0;
658
659 // done with keys (there may be none!);
660 // now set offset to next app in current application
661 if (pAppNode->pNext)
662 pIniAppCurrent->offNextApp = ulCurOfs;
663 else
664 // this was the last one:
665 pIniAppCurrent->offNextApp = 0;
666
667 // next app
668 pAppNode = pAppNode->pNext;
669 }
670
671 // write out everything
672 if (!(arc = DosSetFilePtr(pXIni->hFile,
673 0,
674 FILE_BEGIN,
675 &ulSet)))
676 {
677 ULONG cbWritten = 0;
678 if (!(arc = DosWrite(pXIni->hFile,
679 pbData2Write,
680 ulTotalFileSize,
681 &cbWritten)))
682 {
683 if (!(arc = DosSetFileSize(pXIni->hFile,
684 ulTotalFileSize)))
685 ;
686 }
687 }
688
689 free(pbData2Write);
690 }
691
692 return arc;
693}
694
695/* ******************************************************************
696 *
697 * API Functions
698 *
699 ********************************************************************/
700
701/*
702 *@@ xprfOpenProfile:
703 * opens an extended profile (XINI). This is similar to
704 * PrfOpenProfile, but cannot be used interchangably.
705 * See the top of this file (xprf.c) for general remarks.
706 *
707 * If the full path is not specified, the current
708 * directory is used. This uses DosProtectOpen to
709 * open the profile, so see CPREF for additional remarks.
710 *
711 * If the specified profile does not exist yet, it is
712 * created by this function.
713 *
714 * Note that you must not open the system profiles
715 * (OS2.INI and OS2SYS.INI) using this function because
716 * this would keep OS/2 from updating them.
717 *
718 * This returns 0 (NO_ERROR) on success. Otherwise either
719 * an OS/2 error code (ERROR_*) or one of the profile error
720 * codes defined in prfh.h is returned.
721 */
722
723APIRET xprfOpenProfile(PCSZ pcszFilename, // in: profile name
724 PXINI *ppxini) // out: profile handle
725{
726 APIRET arc = NO_ERROR;
727 PXINI pXIni = NULL;
728 ULONG ulFilenameLen;
729
730 if ( (!pcszFilename)
731 || (!ppxini)
732 )
733 arc = ERROR_INVALID_PARAMETER; // V1.0.0 (2002-09-17) [umoeller]
734 else if (!(ulFilenameLen = strlen(pcszFilename)))
735 arc = ERROR_INVALID_PARAMETER; // V1.0.0 (2002-09-17) [umoeller]
736 else if (ulFilenameLen >= CCHMAXPATH - 1)
737 arc = ERROR_FILENAME_EXCED_RANGE;
738 else
739 {
740 HFILE hFile = NULLHANDLE;
741 ULONG ulAction = 0;
742 // FHLOCK hLock = 0;
743
744 // WarpIN V1.0.20 (2011-07-08) [pr]: add NOINHERIT
745 if (!(arc = DosOpen((PSZ)pcszFilename,
746 &hFile,
747 &ulAction,
748 1024, // initial size
749 FILE_NORMAL,
750 OPEN_ACTION_CREATE_IF_NEW
751 | OPEN_ACTION_OPEN_IF_EXISTS,
752 OPEN_FLAGS_FAIL_ON_ERROR
753 | OPEN_FLAGS_SEQUENTIAL
754 | OPEN_FLAGS_NOINHERIT
755 | OPEN_SHARE_DENYREADWRITE
756 | OPEN_ACCESS_READWRITE,
757 NULL)))
758 {
759 if (!(pXIni = (PXINI)malloc(sizeof(XINI))))
760 arc = ERROR_NOT_ENOUGH_MEMORY;
761 else
762 {
763 // OK: initialize XINI
764 memset(pXIni, 0, sizeof(XINI));
765 memcpy(pXIni->acMagic, XINI_MAGIC_BYTES, sizeof(XINI_MAGIC_BYTES));
766 memcpy(pXIni->szFilename,
767 pcszFilename,
768 ulFilenameLen + 1);
769 pXIni->hFile = hFile;
770 // pXIni->hLock = hLock;
771
772 lstInit(&pXIni->llApps, FALSE);
773
774 if (ulAction == FILE_CREATED)
775 // file newly created: rewrite on close
776 pXIni->fDirty = TRUE;
777 else
778 // file existed: read data
779 if (arc = ReadINI(pXIni))
780 // error:
781 FreeINI(pXIni);
782 }
783
784 if (!arc)
785 *ppxini = pXIni;
786 else
787 DosClose(hFile);
788 }
789 }
790
791 return arc;
792}
793
794/*
795 *@@ xprfQueryProfileSize:
796 * returns the size of INI data, similarly to
797 * what PrfQueryProfileSize does.
798 *
799 * If (pszAppName == NULL), this returns the size of
800 * the buffer required to hold the enumerated list
801 * of application names. pszKey is then ignored.
802 *
803 * Otherwise, if (pszKeyName == NULL), this returns
804 * the size of the buffer required to hold the
805 * enumerated list of _key_ names for the given
806 * application.
807 *
808 * If both pszAppName and pszKeyName are not NULL, this
809 * returns the data size of the given key.
810 *
811 * Returns:
812 *
813 * -- NO_ERROR
814 *
815 *@@added V1.0.0 (2002-09-17) [umoeller]
816 */
817
818APIRET xprfQueryProfileSize(PXINI pXIni, // in: profile opened with xprfOpenProfile
819 PCSZ pcszAppName, // in: application name or NULL
820 PCSZ pcszKeyName, // in: key name or NULL
821 PULONG pulDataLen) // out: size of requested data
822{
823 APIRET arc = NO_ERROR;
824 ULONG ulDataLen = 0;
825
826 if (!pcszAppName)
827 {
828 PLISTNODE pAppNode = lstQueryFirstNode(&pXIni->llApps);
829 while (pAppNode)
830 {
831 PXINIAPPDATA pAppDataThis = (PXINIAPPDATA)pAppNode->pItemData;
832 ulDataLen += strlen(pAppDataThis->pszAppName) + 1;
833 pAppNode = pAppNode->pNext;
834 }
835
836 // extra byte for terminating extra null
837 ++ulDataLen;
838 }
839 else
840 {
841 // app specified:
842 PXINIAPPDATA pAppData;
843
844 if (!(arc = FindApp(pXIni,
845 pcszAppName,
846 &pAppData)))
847 {
848 // app exists:
849
850 if (!pcszKeyName)
851 {
852 // app != NULL, but key == NULL:
853 // return size of keys list
854 PLISTNODE pKeyNode = lstQueryFirstNode(&pAppData->llKeys);
855 while (pKeyNode)
856 {
857 PXINIKEYDATA pKeyDataThis = (PXINIKEYDATA)pKeyNode->pItemData;
858 ulDataLen += strlen(pKeyDataThis->pszKeyName) + 1;
859 pKeyNode = pKeyNode->pNext;
860 }
861
862 // extra byte for terminating extra null
863 ++ulDataLen;
864 }
865 else
866 {
867 // both app and key specified:
868 PXINIKEYDATA pKeyData;
869 if (!(arc = FindKey(pAppData,
870 pcszKeyName,
871 &pKeyData)))
872 ulDataLen = pKeyData->cbData;
873 }
874 }
875 }
876
877 if (pulDataLen)
878 *pulDataLen = ulDataLen;
879
880 return arc;
881}
882
883/*
884 *@@ xprfQueryProfileData:
885 * reads data from the given XINI, similarly to
886 * what PrfQueryProfileData does.
887 *
888 * If (pszAppName == NULL), this returns the
889 * enumerated list of application names.
890 * pszKey is then ignored. *pulBufferMax
891 * receives the total size of the list excluding
892 * the final NULL character.
893 *
894 * Otherwise, if (pszKeyName == NULL), this the
895 * enumerated list of _key_ names for the given
896 * application. *pulBufferMax receives the total
897 * size of the list excluding the final NULL character.
898 *
899 * If both pszAppName and pszKeyName are not NULL,
900 * this returns the data of the given key.
901 * pulBufferMax receives the bytes copied.
902 *
903 * Returns:
904 *
905 * -- NO_ERROR
906 */
907
908APIRET xprfQueryProfileData(PXINI pXIni, // in: profile opened with xprfOpenProfile
909 PCSZ pcszAppName, // in: application name
910 PCSZ pcszKeyName, // in: key name or NULL
911 PVOID pBuffer, // in: buffer to receive data
912 PULONG pulBufferMax) // in: buffer size, out: size of written data
913{
914 APIRET arc = NO_ERROR;
915 ULONG ulDataLen = 0;
916
917 if (!pcszAppName)
918 {
919 PLISTNODE pAppNode = lstQueryFirstNode(&pXIni->llApps);
920 PBYTE pbTarget = (PSZ)pBuffer;
921 ULONG cbCopied = 0;
922 while (pAppNode)
923 {
924 PXINIAPPDATA pAppDataThis = (PXINIAPPDATA)pAppNode->pItemData;
925 ULONG cbThis = strlen(pAppDataThis->pszAppName) + 1;
926 if (cbCopied + cbThis > *pulBufferMax)
927 break;
928 else
929 {
930 memcpy(pbTarget + cbCopied,
931 pAppDataThis->pszAppName,
932 cbThis);
933 cbCopied += cbThis;
934 }
935
936 pAppNode = pAppNode->pNext;
937 }
938
939 // extra byte for terminating extra null
940 pbTarget[cbCopied] = '\0';
941 ulDataLen = cbCopied; // PMREF says terminating null is not counted
942 }
943 else
944 {
945 // app specified:
946 PXINIAPPDATA pAppData;
947
948 if (!(arc = FindApp(pXIni,
949 pcszAppName,
950 &pAppData)))
951 {
952 // app exists:
953
954 if (!pcszKeyName)
955 {
956 // app != NULL, but key == NULL:
957 // return size of keys list
958 PLISTNODE pKeyNode = lstQueryFirstNode(&pAppData->llKeys);
959 PBYTE pbTarget = (PSZ)pBuffer;
960 ULONG cbCopied = 0;
961 while (pKeyNode)
962 {
963 PXINIKEYDATA pKeyDataThis = (PXINIKEYDATA)pKeyNode->pItemData;
964 ULONG cbThis = strlen(pKeyDataThis->pszKeyName) + 1;
965 if (cbCopied + cbThis > *pulBufferMax)
966 break;
967 else
968 {
969 memcpy(pbTarget + cbCopied,
970 pKeyDataThis->pszKeyName,
971 cbThis);
972 cbCopied += cbThis;
973 }
974
975 pKeyNode = pKeyNode->pNext;
976 }
977
978 // extra byte for terminating extra null
979 pbTarget[cbCopied] = '\0';
980 ulDataLen = cbCopied; // PMREF says terminating null is not counted
981 }
982 else
983 {
984 // both app and key specified:
985 PXINIKEYDATA pKeyData;
986 if (!(arc = FindKey(pAppData,
987 pcszKeyName,
988 &pKeyData)))
989 {
990 ulDataLen = min(pKeyData->cbData,
991 *pulBufferMax);
992 memcpy(pBuffer,
993 pKeyData->pbData,
994 ulDataLen);
995 }
996 }
997 }
998 }
999
1000 if (pulBufferMax)
1001 *pulBufferMax = ulDataLen;
1002
1003 return arc;
1004}
1005
1006/*
1007 *@@ xprfQueryProfileInt:
1008 * reads data from the given XINI, similarly to
1009 * what PrfQueryProfileInt does.
1010 *
1011 * You cannot specify HINI_SYSTEM or HINI_USER for
1012 * hINi.
1013 *
1014 *@@added WarpIN V1.0.18 (2008-10-04) [pr]
1015 */
1016
1017LONG xprfQueryProfileInt(PXINI pXIni,
1018 PCSZ pcszApp,
1019 PCSZ pcszKey,
1020 LONG lDefault)
1021{
1022 char szBuffer[20];
1023 LONG lVal = lDefault;
1024 ULONG ulSize = sizeof(szBuffer) - 1;
1025
1026 if (pcszApp && pcszApp[0] && pcszKey && pcszKey[0] &&
1027 !xprfQueryProfileData(pXIni, pcszApp, pcszKey, szBuffer, &ulSize))
1028 {
1029 szBuffer[ulSize] = '\0';
1030 lVal = atol(szBuffer);
1031 }
1032
1033 return lVal;
1034}
1035
1036/*
1037 *@@ xprfWriteProfileData:
1038 * writes data into an extended profile (XINI).
1039 * This operates similar to PrfWriteProfileData,
1040 * that is:
1041 *
1042 * -- If all of pcszApp, pcszKey, pData, and
1043 * ulDataLen are specified, the given data is
1044 * written into the specified application/key
1045 * pair.
1046 *
1047 * -- If pcszApp and pcszKey are specified, but
1048 * pData and ulDataLen are null, the specified
1049 * key is deleted.
1050 *
1051 * -- If pcszApp is specified, but all of pcszKey,
1052 * pData, and ulDataLen are null, the entire
1053 * specified application is deleted.
1054 *
1055 * You cannot specify HINI_SYSTEM or HINI_USER for
1056 * hINi.
1057 *
1058 * Note that if data has been added or removed,
1059 * the INI file on disk is not updated automatically.
1060 * Instead, our memory copy of it is only marked
1061 * as "dirty" so that the file will be rewritten
1062 * on xprfCloseProfile.
1063 *
1064 * Returns:
1065 *
1066 * -- NO_ERROR
1067 */
1068
1069APIRET xprfWriteProfileData(PXINI pXIni, // in: profile opened with xprfOpenProfile
1070 PCSZ pcszApp, // in: application name
1071 PCSZ pcszKey, // in: key name or NULL
1072 PVOID pData, // in: data to write or NULL
1073 ULONG ulDataLen) // in: sizeof(*pData) or null
1074{
1075 APIRET arc = NO_ERROR;
1076
1077 if ( (!pXIni)
1078 || (memcmp(pXIni->acMagic, XINI_MAGIC_BYTES, sizeof(XINI_MAGIC_BYTES)))
1079 )
1080 arc = ERROR_INVALID_PARAMETER;
1081 else
1082 {
1083 // check if application exists
1084 PXINIAPPDATA pAppData;
1085
1086 if (FindApp(pXIni,
1087 pcszApp,
1088 &pAppData))
1089 // not found:
1090 pAppData = NULL;
1091
1092 // now check: does caller want entire application deleted?
1093 if (!pcszKey)
1094 {
1095 // yes, delete application: did we find it?
1096 if (pAppData)
1097 {
1098 // yes: kill that
1099 FreeApp(pAppData);
1100 // and remove from list
1101 lstRemoveItem(&pXIni->llApps, pAppData);
1102
1103 // rewrite profile on close
1104 pXIni->fDirty = TRUE;
1105 }
1106 // else application doesn't exist:
1107 // nothing to do return NO_ERROR
1108 }
1109 else
1110 {
1111 // caller has specified key:
1112 // does caller want a key to be deleted?
1113 if (!ulDataLen)
1114 {
1115 // yes: delete key:
1116 if (pAppData)
1117 {
1118 // app exists:
1119 FreeKeyIfExists(pXIni,
1120 pAppData,
1121 pcszKey);
1122 }
1123 // else app doesn't even exist:
1124 // nothing to do, return NO_ERROR
1125 }
1126 else
1127 {
1128 // key and data specified: let's add something...
1129
1130 if (!pAppData)
1131 // app doesn't exist yet:
1132 // create
1133 arc = CreateApp(pXIni,
1134 pcszApp,
1135 &pAppData);
1136
1137 if (!arc)
1138 {
1139 // found or created app:
1140
1141 // delete existing key if it exists
1142 PXINIKEYDATA pKeyData;
1143
1144 FreeKeyIfExists(pXIni,
1145 pAppData,
1146 pcszKey);
1147
1148 // now create new key
1149 if (!(arc = CreateKey(pAppData,
1150 pcszKey,
1151 (PBYTE)pData,
1152 ulDataLen,
1153 &pKeyData)))
1154 // mark as dirty
1155 pXIni->fDirty = TRUE;
1156 }
1157 }
1158 }
1159 }
1160
1161 return arc;
1162}
1163
1164/*
1165 *@@ xprfWriteProfileString:
1166 * writes string into an extended profile (XINI).
1167 * This operates similar to PrfWriteProfileString.
1168 *
1169 * You cannot specify HINI_SYSTEM or HINI_USER for
1170 * hINi.
1171 *
1172 *@@added WarpIN V1.0.18 (2008-10-04) [pr]
1173 */
1174
1175APIRET xprfWriteProfileString(PXINI pXIni, // in: profile opened with xprfOpenProfile
1176 PCSZ pcszApp, // in: application name
1177 PCSZ pcszKey, // in: key name or NULL
1178 PCSZ pcszString) // in: string to write or NULL
1179{
1180 ULONG ulDataLen = 0;
1181
1182 if (pcszString)
1183 ulDataLen = strlen(pcszString) + 1;
1184
1185 return xprfWriteProfileData(pXIni, pcszApp, pcszKey, (PVOID) pcszString, ulDataLen);
1186}
1187
1188/*
1189 *@@ xprfCloseProfile:
1190 * closes a profile opened with xprfOpenProfile.
1191 * If the profile is "dirty", that is, if any data
1192 * has been changed using xprfWriteProfileData, the
1193 * file is written back to disk before closing.
1194 *
1195 * You cannot specify HINI_SYSTEM or HINI_USER for
1196 * hINi.
1197 *
1198 * Returns:
1199 *
1200 * -- NO_ERROR
1201 */
1202
1203APIRET xprfCloseProfile(PXINI pXIni) // in: profile opened with xprfOpenProfile
1204{
1205 APIRET arc = NO_ERROR;
1206
1207 if ( (!pXIni)
1208 || (memcmp(pXIni->acMagic, XINI_MAGIC_BYTES, sizeof(XINI_MAGIC_BYTES)))
1209 )
1210 arc = ERROR_INVALID_PARAMETER;
1211 else
1212 {
1213 if (pXIni->fDirty)
1214 arc = WriteINI(pXIni);
1215
1216 if (!arc)
1217 {
1218 if (!(arc = DosClose(pXIni->hFile)))
1219 {
1220 pXIni->hFile = 0;
1221
1222 FreeINI(pXIni);
1223 }
1224 }
1225 }
1226
1227 return arc;
1228}
1229
1230/*
1231 *@@ xprfQueryKeysForApp:
1232 * the equivalent of prfhQueryKeysForApp for
1233 * XINI files.
1234 *
1235 *@@added V1.0.0 (2002-09-17) [umoeller]
1236 *@@changed WarpIN V1.0.18 (2008-10-04) [pr]: fixed inverted logic bugs
1237 */
1238
1239APIRET xprfQueryKeysForApp(PXINI hIni, // in: INI handle
1240 PCSZ pcszApp, // in: application to query list for (or NULL for applications list)
1241 PSZ *ppszKeys) // out: keys list (newly allocated)
1242{
1243 APIRET arc = NO_ERROR;
1244 PSZ pKeys = NULL;
1245 ULONG ulSizeOfKeysList = 0;
1246
1247 // get size of keys list for pszApp
1248 if (xprfQueryProfileSize(hIni, pcszApp, NULL, &ulSizeOfKeysList))
1249 arc = PRFERR_KEYSLIST;
1250 else
1251 {
1252 if (ulSizeOfKeysList == 0)
1253 ulSizeOfKeysList = 1; // V0.9.19 (2002-04-11) [pr]
1254
1255 if (!(pKeys = (PSZ)malloc(ulSizeOfKeysList)))
1256 arc = ERROR_NOT_ENOUGH_MEMORY;
1257 else
1258 {
1259 *pKeys = 0;
1260 if (xprfQueryProfileData(hIni, pcszApp, NULL, pKeys, &ulSizeOfKeysList))
1261 arc = PRFERR_KEYSLIST;
1262 }
1263 }
1264
1265 if (!arc) // V0.9.12 (2001-05-12) [umoeller]
1266 *ppszKeys = pKeys;
1267 else
1268 if (pKeys)
1269 free(pKeys);
1270
1271 return arc;
1272}
1273
1274/*
1275 *@@ xprfhQueryProfileData:
1276 * the equivalent of prfhQueryProfileData for
1277 * XINI files.
1278 *
1279 *@@added WarpIN V1.0.18 (2008-10-04) [pr]
1280 */
1281
1282PSZ xprfhQueryProfileData(PXINI pXIni, // in: INI handle
1283 PCSZ pcszApp, // in: application to query
1284 PCSZ pcszKey, // in: key to query
1285 PULONG pcbBuf) // out: size of the returned buffer; ptr can be NULL
1286{
1287 PSZ pData = NULL;
1288 ULONG ulSizeOfData;
1289
1290 // get size of data for pcszApp/pcszKey
1291 if ( (!xprfQueryProfileSize(pXIni, (PSZ)pcszApp, (PSZ)pcszKey, &ulSizeOfData))
1292 && (ulSizeOfData)
1293 && (pData = (PSZ)malloc(ulSizeOfData))
1294 )
1295 {
1296 if (xprfQueryProfileData(pXIni, (PSZ)pcszApp, (PSZ)pcszKey, pData, &ulSizeOfData))
1297 {
1298 free(pData);
1299 pData = NULL;
1300 }
1301 }
1302
1303 if (pcbBuf)
1304 *pcbBuf = ulSizeOfData;
1305
1306 return pData;
1307}
1308
Note: See TracBrowser for help on using the repository browser.