Subversion Repositories Games.Chess Giants

Rev

Rev 1 | Rev 161 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1 Rev 136
Line 5... Line 5...
5
 
5
 
6
// WARNING: INI SECTION NAMES ARE CASE SENSITIVE, BUT KEY NAMES ARE NOT!
6
// WARNING: INI SECTION NAMES ARE CASE SENSITIVE, BUT KEY NAMES ARE NOT!
7
 
7
 
8
 
8
 
9
// internal definitions
9
// internal definitions
10
#define MAX_KEY_SIZE 124
-
 
11
#define MAX_VALUE_SIZE 3968
-
 
12
#define DICTIONARY_PAGE_SIZE 128
10
#define DICTIONARY_PAGE_SIZE 128
-
 
11
#define STRING_MAXSIZE 65536
13
#define INI_SECTION_SEPARATOR ']'
12
#define INI_SECTION_SEPARATOR ']'
14
#define INI_INVALID_KEY (wchar_t *) 0x7fffffff
13
#define INI_INVALID_KEY (wchar_t *) 0x7fffffff
15
#define WSIZEOF(a) (sizeof (a) / sizeof (wchar_t))
14
#define WSIZEOF(a) (sizeof (a) / sizeof (wchar_t))
16
 
15
 
17
 
16
 
18
// dictionary structure definitions
17
// dictionary structure definitions
19
typedef struct dictionary_entry_s
18
typedef struct dictionary_entry_s
20
{
19
{
21
   wchar_t key[MAX_KEY_SIZE]; // key string
20
   wchar_t *key; // key string (mallocated)
22
   unsigned long hash; // key hash value
21
   unsigned long hash; // key hash value
23
   wchar_t value[MAX_VALUE_SIZE]; // value string
22
   wchar_t *value; // value string (mallocated)
24
} dictionary_entry_t;
23
} dictionary_entry_t;
25
 
24
 
26
 
25
 
27
typedef struct dictionary_s
26
typedef struct dictionary_s
28
{
27
{
Line 64... Line 63...
64
unsigned char INIFile_SaveINIFile (const wchar_t *filename, void *ini_data);
63
unsigned char INIFile_SaveINIFile (const wchar_t *filename, void *ini_data);
65
void INIFile_FreeINIFile (void *ini_data);
64
void INIFile_FreeINIFile (void *ini_data);
66
 
65
 
67
 
66
 
68
// internal variables
67
// internal variables
69
static wchar_t *INIFile_default_section = L"__default";
68
static wchar_t *INIFile_default_section = L"__default"; // MUST BE A READ-WRITE VARIABLE AND NOT A DEFINE
70
static wchar_t line_buffer[MAX_KEY_SIZE + MAX_VALUE_SIZE];
-
 
71
static wchar_t temp_key[MAX_KEY_SIZE];
-
 
72
static wchar_t number_as_string[256];
-
 
73
static wchar_t temp_section[MAX_KEY_SIZE];
-
 
74
static wchar_t temp_entry[MAX_KEY_SIZE];
-
 
75
static wchar_t temp_value[MAX_VALUE_SIZE];
-
 
76
 
69
 
77
 
70
 
78
static dictionary_t *Dictionary_CreateDictionary (int size)
71
static dictionary_t *Dictionary_CreateDictionary (int size)
79
{
72
{
80
   // this function allocates a new dictionary object of given size and returns it. If you do
73
   // this function allocates a new dictionary object of given size and returns it. If you do
Line 98... Line 91...
98
 
91
 
99
 
92
 
100
static void Dictionary_DestroyDictionary (dictionary_t *dictionary)
93
static void Dictionary_DestroyDictionary (dictionary_t *dictionary)
101
{
94
{
102
   // frees a dictionary object and all memory associated to it.
95
   // frees a dictionary object and all memory associated to it.
-
 
96
 
-
 
97
   int entry_index;
103
 
98
 
104
   if (dictionary == NULL)
99
   if (dictionary == NULL)
105
      return; // consistency check
100
      return; // consistency check
-
 
101
 
-
 
102
   for (entry_index = 0; entry_index < dictionary->entry_count; entry_index++)
-
 
103
   {
-
 
104
      SAFE_free ((void **) &dictionary->entries[entry_index].key); // free all dictionary keys
-
 
105
      SAFE_free ((void **) &dictionary->entries[entry_index].value); // free all dictionary values
-
 
106
   }
106
 
107
 
107
   SAFE_free ((void **) &dictionary->entries); // free the entries array
108
   SAFE_free ((void **) &dictionary->entries); // free the entries array
108
   SAFE_free ((void **) &dictionary); // and finally, free the dictionary itself
109
   SAFE_free ((void **) &dictionary); // and finally, free the dictionary itself
109
 
110
 
110
   return; // finished
111
   return; // finished
Line 159... Line 160...
159
   // value is replaced by the provided one. If the key cannot be found in the dictionary, it
160
   // value is replaced by the provided one. If the key cannot be found in the dictionary, it
160
   // is added to it.
161
   // is added to it.
161
 
162
 
162
   unsigned long hash;
163
   unsigned long hash;
163
   register int entry_index;
164
   register int entry_index;
-
 
165
   size_t bufsize;
164
 
166
 
165
   hash = Dictionary_ComputeHashValueForKey (key); // compute hash for this key
167
   hash = Dictionary_ComputeHashValueForKey (key); // compute hash for this key
166
 
168
 
167
   // for each entry in the dictionary...
169
   // for each entry in the dictionary...
168
   for (entry_index = 0; entry_index < dictionary->entry_count; entry_index++)
170
   for (entry_index = 0; entry_index < dictionary->entry_count; entry_index++)
Line 173... Line 175...
173
      // does that key have the same hash value AND the same name ?
175
      // does that key have the same hash value AND the same name ?
174
      if ((hash == dictionary->entries[entry_index].hash) && (wcscmp (key, dictionary->entries[entry_index].key) == 0))
176
      if ((hash == dictionary->entries[entry_index].hash) && (wcscmp (key, dictionary->entries[entry_index].key) == 0))
175
      {
177
      {
176
         // we've found the right key: modify its value and return
178
         // we've found the right key: modify its value and return
177
 
179
 
178
         // have we provided a valid value ?
-
 
179
         if (value != NULL)
180
         if (value == NULL)
180
            wcscpy_s (dictionary->entries[entry_index].value, WSIZEOF (dictionary->entries[entry_index].value), value); // copy the value string
181
            value = L""; // if a null value was specified, use an empty string
-
 
182
 
181
         else
183
         bufsize = wcslen (value) + 1;
-
 
184
         dictionary->entries[entry_index].value = (wchar_t *) SAFE_realloc (dictionary->entries[entry_index].value, 0, bufsize, sizeof (wchar_t), false);
182
            dictionary->entries[entry_index].value[0] = 0; // reset the value string
185
         wcscpy_s (dictionary->entries[entry_index].value, bufsize, value); // copy the value string
183
 
186
 
184
         return; // value has been modified: return
187
         return; // value has been modified: return
185
      }
188
      }
186
   }
189
   }
187
 
190
 
Line 199... Line 202...
199
      dictionary->entries = (dictionary_entry_t *) SAFE_realloc (dictionary->entries, dictionary->size, dictionary->size + DICTIONARY_PAGE_SIZE, sizeof (dictionary_entry_t), false); // alloc 1 more page
202
      dictionary->entries = (dictionary_entry_t *) SAFE_realloc (dictionary->entries, dictionary->size, dictionary->size + DICTIONARY_PAGE_SIZE, sizeof (dictionary_entry_t), false); // alloc 1 more page
200
      dictionary->size += DICTIONARY_PAGE_SIZE; // increase dictionary size
203
      dictionary->size += DICTIONARY_PAGE_SIZE; // increase dictionary size
201
   }
204
   }
202
 
205
 
203
   // copy the new key
206
   // copy the new key
204
 
-
 
-
 
207
   bufsize = wcslen (key) + 1;
-
 
208
   dictionary->entries[entry_index].key = (wchar_t *) SAFE_malloc (bufsize, sizeof (wchar_t), false);
205
   wcscpy_s (dictionary->entries[entry_index].key, WSIZEOF (dictionary->entries[entry_index].key), key); // copy the key string...
209
   wcscpy_s (dictionary->entries[entry_index].key, bufsize, key); // copy the key string...
206
   dictionary->entries[entry_index].hash = hash; // ...and store the hash value
210
   dictionary->entries[entry_index].hash = hash; // ...and store the hash value
207
 
211
 
208
   // have we provided a valid value ?
212
   // copy the new value
209
   if (value != NULL)
213
   if (value == NULL)
210
      wcscpy_s (dictionary->entries[entry_index].value, WSIZEOF (dictionary->entries[entry_index].value), value); // copy the value string
214
      value = L""; // if a null value was specified, use an empty string
211
   else
215
   bufsize = wcslen (value) + 1;
-
 
216
   dictionary->entries[entry_index].value = (wchar_t *) SAFE_malloc (bufsize, sizeof (wchar_t), false);
212
      dictionary->entries[entry_index].value[0] = 0; // reset the value string
217
   wcscpy_s (dictionary->entries[entry_index].value, bufsize, value); // copy the value string
213
 
218
 
214
   dictionary->entry_count++; // there is one more entry in the dictionary now
219
   dictionary->entry_count++; // there is one more entry in the dictionary now
215
   return;
220
   return;
216
}
221
}
217
 
222
 
Line 237... Line 242...
237
   }
242
   }
238
 
243
 
239
   if (entry_index == dictionary->entry_count)
244
   if (entry_index == dictionary->entry_count)
240
      return; // if key was not found, just return
245
      return; // if key was not found, just return
241
 
246
 
242
   // clear the key, the hash and its value data
247
   // free its buffers, then clear the key, the hash and its value data
-
 
248
   SAFE_free ((void **) &dictionary->entries[entry_index].key);
-
 
249
   SAFE_free ((void **) &dictionary->entries[entry_index].value);
243
   memset (&dictionary->entries[entry_index], 0, sizeof (dictionary_entry_t));
250
   memset (&dictionary->entries[entry_index], 0, sizeof (dictionary_entry_t));
244
 
251
 
245
   dictionary->entry_count--; // there is one entry less in the dictionary now
252
   dictionary->entry_count--; // there is one entry less in the dictionary now
246
   return;
253
   return;
247
}
254
}
Line 409... Line 416...
409
   if (section == NULL)
416
   if (section == NULL)
410
      section = INIFile_default_section; // if no section was provided, use empty section name
417
      section = INIFile_default_section; // if no section was provided, use empty section name
411
 
418
 
412
   dictionary = (dictionary_t *) ini_data; // quick access to dictionary
419
   dictionary = (dictionary_t *) ini_data; // quick access to dictionary
413
 
420
 
414
   // build the key entry prefix
-
 
415
   swprintf_s (temp_key, WSIZEOF (temp_key), L"%s%c", section, INI_SECTION_SEPARATOR); // compose the key
-
 
416
   length = wcslen (temp_key);
421
   length = wcslen (section);
417
 
422
 
418
   // cycle through all remaining entries
423
   // cycle through all remaining entries
419
   found_keys = 0;
424
   found_keys = 0;
420
   for (i = 0; i < dictionary->entry_count; i++)
425
   for (i = 0; i < dictionary->entry_count; i++)
421
   {
426
   {
422
      entry = &dictionary->entries[i]; // quick access to each entry
427
      entry = &dictionary->entries[i]; // quick access to each entry
423
 
428
 
424
      if (wcsncmp (entry->key, temp_key, length) != 0)
429
      if ((wcsncmp (entry->key, section, length) != 0) || (entry->key[length] != INI_SECTION_SEPARATOR))
425
         continue; // if this key doesn't belong to the wanted section, skip it
430
         continue; // if this key doesn't belong to the wanted section, skip it
426
 
431
 
427
      // this key belongs to the wanted section. Is it the key we want ?
432
      // this key belongs to the wanted section. Is it the key we want ?
428
      if (found_keys == entry_index)
433
      if (found_keys == entry_index)
429
         return (&entry->key[length]); // if so, return its name
434
         return (&entry->key[length + 1]); // if so, return its name
430
 
435
 
431
      found_keys++; // it wasn't the key we want, so increase counter and proceed to the next one
436
      found_keys++; // it wasn't the key we want, so increase counter and proceed to the next one
432
   }
437
   }
433
 
438
 
434
   return (NULL); // if not found, return NULL
439
   return (NULL); // if not found, return NULL
Line 528... Line 533...
528
   // this function queries a dictionary for a key. A key as read from an ini file is given as
533
   // this function queries a dictionary for a key. A key as read from an ini file is given as
529
   // "section]key". If the key cannot be found, the pointer passed as 'def' is returned. The
534
   // "section]key". If the key cannot be found, the pointer passed as 'def' is returned. The
530
   // returned char pointer points to a string allocated in the dictionary, do not free or
535
   // returned char pointer points to a string allocated in the dictionary, do not free or
531
   // modify it.
536
   // modify it.
532
 
537
 
533
   int length;
538
   size_t length;
534
   int i;
539
   size_t i;
-
 
540
   size_t keysize;
-
 
541
   wchar_t *key;
535
   wchar_t *value;
542
   wchar_t *value;
536
 
543
 
537
   if (ini_data == NULL)
544
   if (ini_data == NULL)
538
      return (default_value); // consistency check
545
      return (default_value); // consistency check
539
 
546
 
540
   if (section == NULL)
547
   if (section == NULL)
541
      section = INIFile_default_section; // if no section was provided, use empty section name
548
      section = INIFile_default_section; // if no section was provided, use empty section name
-
 
549
 
-
 
550
   // allocate some space for the dictionary key name
-
 
551
   keysize = wcslen (section) + 1 + wcslen (entry) + 1;
-
 
552
   key = (wchar_t *) SAFE_malloc (keysize, sizeof (wchar_t), false);
542
 
553
 
543
   // if we were given an entry, build a key as section]entry
554
   // if we were given an entry, build a key as section]entry
544
   if (entry != NULL)
555
   if (entry != NULL)
545
   {
556
   {
546
      swprintf_s (temp_key, WSIZEOF (temp_key), L"%s%c%s", section, INI_SECTION_SEPARATOR, entry); // compose the key
557
      swprintf_s (key, keysize, L"%s%c%s", section, INI_SECTION_SEPARATOR, entry); // compose the key
547
 
558
 
548
      i = (int) wcslen (temp_key); // get the key string length
559
      i = wcslen (key); // get the key string length
549
      if (i < WSIZEOF (temp_key))
560
      if (i < keysize)
550
         length = i;
561
         length = i;
551
      else
562
      else
552
         length = WSIZEOF (temp_key) - 1; // clamp it to a max value
563
         length = keysize - 1; // clamp it to a max value
553
 
564
 
554
      // for each character in the string after the section separator...
565
      // for each character in the string after the section separator...
555
      for (i = (int) wcslen (section) + 1; i < length; i++)
566
      for (i = wcslen (section) + 1; i < length; i++)
556
         temp_key[i] = towlower (temp_key[i]); // convert it to lowercase
567
         key[i] = towlower (key[i]); // convert it to lowercase
557
      temp_key[i] = 0; // terminate the string
568
      key[i] = 0; // terminate the string
558
   }
569
   }
559
 
570
 
560
   // else it must be a section name
571
   // else it must be a section name
561
   else
572
   else
562
      wcscpy_s (temp_key, WSIZEOF (temp_key), section); // copy the name into the key
573
      wcscpy_s (key, keysize, section); // copy the name into the key
563
 
574
 
564
   value = Dictionary_ReadKey ((dictionary_t *) ini_data, temp_key, default_value); // query the dictionary...
575
   value = Dictionary_ReadKey ((dictionary_t *) ini_data, key, default_value); // query the dictionary...
-
 
576
   SAFE_free ((void **) &key); // free the key name, we no longer need it
565
   return (value); // ...and return the value
577
   return (value); // ...and return the value
566
}
578
}
567
 
579
 
568
 
580
 
569
void INIFile_WriteEntryAsBool (void *ini_data, wchar_t *section, wchar_t *entry, unsigned char value)
581
void INIFile_WriteEntryAsBool (void *ini_data, wchar_t *section, wchar_t *entry, unsigned char value)
Line 584... Line 596...
584
void INIFile_WriteEntryAsLong (void *ini_data, wchar_t *section, wchar_t *entry, long value)
596
void INIFile_WriteEntryAsLong (void *ini_data, wchar_t *section, wchar_t *entry, long value)
585
{
597
{
586
   // sets an entry in a dictionary. If the given entry can be found in the dictionary, it is
598
   // sets an entry in a dictionary. If the given entry can be found in the dictionary, it is
587
   // modified to contain the provided value. If it cannot be found, it is created.
599
   // modified to contain the provided value. If it cannot be found, it is created.
588
 
600
 
589
   // build the long integer value equivalent string (use printf facility)
-
 
590
   swprintf_s (number_as_string, WSIZEOF (number_as_string), L"%ld", value);
601
   wchar_t *number_as_string;
591
 
602
 
-
 
603
   // allocate some space for the number's string representation
-
 
604
   number_as_string = (wchar_t *) SAFE_malloc (32, sizeof (wchar_t), false);
-
 
605
 
-
 
606
   // build the long integer value equivalent string (use printf facility)
-
 
607
   swprintf_s (number_as_string, 32, L"%ld", value);
592
   INIFile_WriteEntryAsString ((dictionary_t *) ini_data, section, entry, number_as_string); // write the new entry
608
   INIFile_WriteEntryAsString ((dictionary_t *) ini_data, section, entry, number_as_string); // write the new entry
-
 
609
 
-
 
610
   SAFE_free ((void **) &number_as_string); // free the number's string representation, we no longer need it
593
   return; // finished
611
   return; // finished
594
}
612
}
595
 
613
 
596
 
614
 
597
void INIFile_WriteEntryAsUnsignedLong (void *ini_data, wchar_t *section, wchar_t *entry, unsigned long value)
615
void INIFile_WriteEntryAsUnsignedLong (void *ini_data, wchar_t *section, wchar_t *entry, unsigned long value)
598
{
616
{
599
   // sets an entry in a dictionary. If the given entry can be found in the dictionary, it is
617
   // sets an entry in a dictionary. If the given entry can be found in the dictionary, it is
600
   // modified to contain the provided value. If it cannot be found, it is created.
618
   // modified to contain the provided value. If it cannot be found, it is created.
601
 
619
 
602
   // build the long integer value equivalent string (use printf facility)
-
 
603
   swprintf_s (number_as_string, WSIZEOF (number_as_string), L"%lu", value);
620
   wchar_t *number_as_string;
604
 
621
 
-
 
622
   // allocate some space for the number's string representation
-
 
623
   number_as_string = (wchar_t *) SAFE_malloc (32, sizeof (wchar_t), false);
-
 
624
 
-
 
625
   // build the long integer value equivalent string (use printf facility)
-
 
626
   swprintf_s (number_as_string, 32, L"%lu", value);
605
   INIFile_WriteEntryAsString ((dictionary_t *) ini_data, section, entry, number_as_string); // write the new entry
627
   INIFile_WriteEntryAsString ((dictionary_t *) ini_data, section, entry, number_as_string); // write the new entry
-
 
628
 
-
 
629
   SAFE_free ((void **) &number_as_string); // free the number's string representation, we no longer need it
606
   return; // finished
630
   return; // finished
607
}
631
}
608
 
632
 
609
 
633
 
610
void INIFile_WriteEntryAsDouble (void *ini_data, wchar_t *section, wchar_t *entry, double value)
634
void INIFile_WriteEntryAsDouble (void *ini_data, wchar_t *section, wchar_t *entry, double value)
611
{
635
{
612
   // sets an entry in a dictionary. If the given entry can be found in the dictionary, it is
636
   // sets an entry in a dictionary. If the given entry can be found in the dictionary, it is
613
   // modified to contain the provided value. If it cannot be found, it is created.
637
   // modified to contain the provided value. If it cannot be found, it is created.
614
 
638
 
615
   // build the long integer value equivalent string (use printf facility)
-
 
616
   swprintf_s (number_as_string, WSIZEOF (number_as_string), L"%g", value);
639
   wchar_t *number_as_string;
617
 
640
 
-
 
641
   // allocate some space for the number's string representation
-
 
642
   number_as_string = (wchar_t *) SAFE_malloc (64, sizeof (wchar_t), false);
-
 
643
 
-
 
644
   // build the long integer value equivalent string (use printf facility)
-
 
645
   swprintf_s (number_as_string, 64, L"%g", value);
618
   INIFile_WriteEntryAsString ((dictionary_t *) ini_data, section, entry, number_as_string); // write the new entry
646
   INIFile_WriteEntryAsString ((dictionary_t *) ini_data, section, entry, number_as_string); // write the new entry
-
 
647
 
-
 
648
   SAFE_free ((void **) &number_as_string); // free the number's string representation, we no longer need it
619
   return; // finished
649
   return; // finished
620
}
650
}
621
 
651
 
622
 
652
 
623
void INIFile_WriteEntryAsString (void *ini_data, wchar_t *section, wchar_t *entry, wchar_t *value)
653
void INIFile_WriteEntryAsString (void *ini_data, wchar_t *section, wchar_t *entry, wchar_t *value)
624
{
654
{
625
   // sets an entry in a dictionary. If the given entry can be found in the dictionary, it is
655
   // sets an entry in a dictionary. If the given entry can be found in the dictionary, it is
626
   // modified to contain the provided value. If it cannot be found, it is created.
656
   // modified to contain the provided value. If it cannot be found, it is created.
627
 
657
 
628
   int length;
658
   size_t length;
629
   int i;
659
   size_t i;
-
 
660
   size_t keysize;
-
 
661
   wchar_t *key;
630
 
662
 
631
   if (ini_data == NULL)
663
   if (ini_data == NULL)
632
      return; // consistency check
664
      return; // consistency check
633
 
665
 
634
   if (section == NULL)
666
   if (section == NULL)
635
      section = INIFile_default_section; // if no section was provided, use empty section name
667
      section = INIFile_default_section; // if no section was provided, use empty section name
-
 
668
 
-
 
669
   // allocate some space for the dictionary key name
-
 
670
   keysize = wcslen (section) + 1 + (entry != NULL ? wcslen (entry) + 1 : 0);
-
 
671
   key = (wchar_t *) SAFE_malloc (keysize, sizeof (wchar_t), false);
636
 
672
 
637
   // if we were given an entry, build a key as section#entry
673
   // if we were given an entry, build a key as section#entry
638
   if (entry != NULL)
674
   if (entry != NULL)
639
   {
675
   {
640
      Dictionary_WriteKey ((dictionary_t *) ini_data, section, NULL); // create the section if it doesn't exist
676
      Dictionary_WriteKey ((dictionary_t *) ini_data, section, NULL); // create the section if it doesn't exist
641
 
677
 
642
      swprintf_s (temp_key, WSIZEOF (temp_key), L"%s%c%s", section, INI_SECTION_SEPARATOR, entry); // compose the key
678
      swprintf_s (key, keysize, L"%s%c%s", section, INI_SECTION_SEPARATOR, entry); // compose the key
643
 
679
 
644
      i = (int) wcslen (temp_key); // get the key string length
680
      i = wcslen (key); // get the key string length
645
      if (i < WSIZEOF (temp_key))
681
      if (i < keysize)
646
         length = i;
682
         length = i;
647
      else
683
      else
648
         length = WSIZEOF (temp_key) - 1; // clamp it to a max value
684
         length = keysize - 1; // clamp it to a max value
649
 
685
 
650
      // for each character in the string after the section separator...
686
      // for each character in the string after the section separator...
651
      for (i = (int) wcslen (section) + 1; i < length; i++)
687
      for (i = wcslen (section) + 1; i < length; i++)
652
         temp_key[i] = towlower (temp_key[i]); // convert it to lowercase
688
         key[i] = towlower (key[i]); // convert it to lowercase
653
      temp_key[i] = 0; // terminate the string
689
      key[i] = 0; // terminate the string
654
   }
690
   }
655
 
691
 
656
   // else it must be a section name
692
   // else it must be a section name
657
   else
693
   else
658
      wcscpy_s (temp_key, WSIZEOF (temp_key), section); // copy the name into the key
694
      wcscpy_s (key, keysize, section); // copy the name into the key
659
 
695
 
660
   Dictionary_WriteKey ((dictionary_t *) ini_data, temp_key, value); // write the new key in the dictionary
696
   Dictionary_WriteKey ((dictionary_t *) ini_data, key, value); // write the new key in the dictionary
-
 
697
   SAFE_free ((void **) &key); // free the key name, we no longer need it
661
   return; // finished
698
   return; // finished
662
}
699
}
663
 
700
 
664
 
701
 
665
void INIFile_DeleteEntry (void *ini_data, wchar_t *section, wchar_t *entry)
702
void INIFile_DeleteEntry (void *ini_data, wchar_t *section, wchar_t *entry)
666
{
703
{
667
   // deletes an entry in the dictionary
704
   // deletes an entry in the dictionary
668
 
705
 
669
   int length;
706
   size_t length;
670
   int i;
707
   size_t i;
-
 
708
   size_t keysize;
-
 
709
   wchar_t *key;
671
 
710
 
672
   if (ini_data == NULL)
711
   if (ini_data == NULL)
673
      return; // consistency check
712
      return; // consistency check
674
 
713
 
675
   if (section == NULL)
714
   if (section == NULL)
676
      section = INIFile_default_section; // if no section was provided, use empty section name
715
      section = INIFile_default_section; // if no section was provided, use empty section name
-
 
716
 
-
 
717
   // allocate some space for the dictionary key name
-
 
718
   keysize = wcslen (section) + 1 + wcslen (entry) + 1;
-
 
719
   key = (wchar_t *) SAFE_malloc (keysize, sizeof (wchar_t), false);
677
 
720
 
678
   // if we were given an entry, build a key as section#entry
721
   // if we were given an entry, build a key as section#entry
679
   if (entry != NULL)
722
   if (entry != NULL)
680
   {
723
   {
681
      swprintf_s (temp_key, WSIZEOF (temp_key), L"%s%c%s", section, INI_SECTION_SEPARATOR, entry); // compose the key
724
      swprintf_s (key, keysize, L"%s%c%s", section, INI_SECTION_SEPARATOR, entry); // compose the key
682
 
725
 
683
      i = (int) wcslen (temp_key); // get the key string length
726
      i = wcslen (key); // get the key string length
684
      if (i < WSIZEOF (temp_key))
727
      if (i < keysize)
685
         length = i;
728
         length = i;
686
      else
729
      else
687
         length = WSIZEOF (temp_key) - 1; // clamp it to a max value
730
         length = keysize - 1; // clamp it to a max value
688
 
731
 
689
      // for each character in the string after the section separator...
732
      // for each character in the string after the section separator...
690
      for (i = (int) wcslen (section) + 1; i < length; i++)
733
      for (i = wcslen (section) + 1; i < length; i++)
691
         temp_key[i] = towlower (temp_key[i]); // convert it to lowercase
734
         key[i] = towlower (key[i]); // convert it to lowercase
692
      temp_key[i] = 0; // terminate the string
735
      key[i] = 0; // terminate the string
693
   }
736
   }
694
 
737
 
695
   // else it must be a section name
738
   // else it must be a section name
696
   else
739
   else
697
      wcscpy_s (temp_key, WSIZEOF (temp_key), section); // copy the name into the key
740
      wcscpy_s (key, keysize, section); // copy the name into the key
698
 
741
 
699
   Dictionary_DeleteKey ((dictionary_t *) ini_data, temp_key);
742
   Dictionary_DeleteKey ((dictionary_t *) ini_data, key);
-
 
743
   SAFE_free ((void **) &key); // free the key name, we no longer need it
700
   return;
744
   return;
701
}
745
}
702
 
746
 
703
 
747
 
704
void INIFile_DeleteSection (void *ini_data, wchar_t *section)
748
void INIFile_DeleteSection (void *ini_data, wchar_t *section)
Line 706... Line 750...
706
   // deletes a whole INI section in the dictionary
750
   // deletes a whole INI section in the dictionary
707
 
751
 
708
   int length;
752
   int length;
709
   int i;
753
   int i;
710
   dictionary_t *dictionary;
754
   dictionary_t *dictionary;
-
 
755
   dictionary_entry_t *entry;
711
 
756
 
712
   if (ini_data == NULL)
757
   if (ini_data == NULL)
713
      return; // consistency check
758
      return; // consistency check
714
 
759
 
715
   if (section == NULL)
760
   if (section == NULL)
716
      section = INIFile_default_section; // if no section was provided, use empty section name
761
      section = INIFile_default_section; // if no section was provided, use empty section name
717
 
762
 
718
   dictionary = (dictionary_t *) ini_data;
763
   dictionary = (dictionary_t *) ini_data;
719
 
764
 
720
   swprintf_s (temp_key, WSIZEOF (temp_key), L"%s%c", section, INI_SECTION_SEPARATOR); // compose the key
-
 
721
   length = (int) wcslen (temp_key); // get the key string length
765
   length = (int) wcslen (section); // get the section string length
722
 
766
 
723
   // for each entry in the dictionary...
767
   // for each entry in the dictionary...
724
   for (i = 0; i < dictionary->entry_count; i++)
768
   for (i = 0; i < dictionary->entry_count; i++)
725
   {
769
   {
-
 
770
      entry = &dictionary->entries[i]; // quick access to each entry
-
 
771
 
726
      if (dictionary->entries[i].key[0] == 0)
772
      if (entry->key[0] == 0)
727
         continue; // skip empty slots
773
         continue; // skip empty slots
728
 
774
 
729
      // does this entry belong to the section we want ?
775
      // does this entry belong to the section we want ?
730
      if (wcsncmp (dictionary->entries[i].key, temp_key, length) == 0)
776
      if ((wcsncmp (entry->key, section, length) == 0) && (entry->key[length] == INI_SECTION_SEPARATOR))
731
         Dictionary_DeleteKey (dictionary, dictionary->entries[i].key); // yes, delete it
777
         Dictionary_DeleteKey (dictionary, entry->key); // yes, delete it
732
   }
778
   }
733
 
779
 
734
   Dictionary_DeleteKey (dictionary, section); // and finally delete the section name itself
780
   Dictionary_DeleteKey (dictionary, section); // and finally delete the section name itself
735
   return;
781
   return;
736
}
782
}
Line 740... Line 786...
740
{
786
{
741
   // this is the parser for ini files. This function is called, providing the name of the file
787
   // this is the parser for ini files. This function is called, providing the name of the file
742
   // to be read. It returns a dictionary object that should not be accessed directly, but
788
   // to be read. It returns a dictionary object that should not be accessed directly, but
743
   // through accessor functions instead.
789
   // through accessor functions instead.
744
 
790
 
-
 
791
   wchar_t *line_buffer;
745
   FILE *fp;
792
   FILE *fp;
746
   int fieldstart;
793
   int fieldstart;
747
   int fieldstop;
794
   int fieldstop;
748
   int length;
795
   int length;
749
   int i;
796
   int i;
750
   dictionary_t *dictionary;
797
   dictionary_t *dictionary;
-
 
798
   wchar_t *current_section;
-
 
799
   wchar_t *current_entry;
-
 
800
   wchar_t *current_value;
751
 
801
 
752
   // try to open the INI file in ASCII read-only mode
802
   // try to open the INI file in ASCII read-only mode
753
   fp = _wfsopen (filename, L"r, ccs=UNICODE", _SH_DENYNO);
803
   fp = _wfsopen (filename, L"r, ccs=UNICODE", _SH_DENYNO);
754
   if (fp == NULL)
804
   if (fp == NULL)
755
      return (NULL); // cancel if file not found
805
      return (NULL); // cancel if file not found
756
 
806
 
757
   dictionary = Dictionary_CreateDictionary (0);
807
   dictionary = Dictionary_CreateDictionary (0);
-
 
808
 
-
 
809
   // allocate some space for the current section, entry and values
-
 
810
   current_section = (wchar_t *) SAFE_malloc (STRING_MAXSIZE, sizeof (wchar_t), false);
-
 
811
   current_entry = (wchar_t *) SAFE_malloc (STRING_MAXSIZE, sizeof (wchar_t), false);
-
 
812
   current_value = (wchar_t *) SAFE_malloc (STRING_MAXSIZE, sizeof (wchar_t), false);
758
 
813
 
759
   // set the default section for orphaned entries and add it to the dictionary
814
   // set the default section for orphaned entries and add it to the dictionary
760
   wcscpy_s (temp_section, WSIZEOF (temp_section), INIFile_default_section);
815
   wcscpy_s (current_section, STRING_MAXSIZE, INIFile_default_section);
761
   INIFile_WriteEntryAsString (dictionary, temp_section, NULL, NULL);
816
   INIFile_WriteEntryAsString (dictionary, current_section, NULL, NULL);
-
 
817
 
-
 
818
   // allocate some space for a line buffer
-
 
819
   line_buffer = (wchar_t *) SAFE_malloc (STRING_MAXSIZE + STRING_MAXSIZE, sizeof (wchar_t), false);
762
 
820
 
763
   // read line per line...
821
   // read line per line...
764
   while (fgetws (line_buffer, WSIZEOF (line_buffer), fp) != NULL)
822
   while (fgetws (line_buffer, STRING_MAXSIZE + STRING_MAXSIZE, fp) != NULL)
765
   {
823
   {
766
      length = (int) wcslen (line_buffer); // get line length
824
      length = (int) wcslen (line_buffer); // get line length
767
 
825
 
768
      while ((length > 0) && ((line_buffer[length - 1] == '\n') || (line_buffer[length - 1] == '\r')))
826
      while ((length > 0) && ((line_buffer[length - 1] == '\n') || (line_buffer[length - 1] == '\r')))
769
         length--; // discard trailing newlines
827
         length--; // discard trailing newlines
Line 782... Line 840...
782
 
840
 
783
      if ((line_buffer[0] == ';') || (line_buffer[0] == '#') || (line_buffer[0] == 0))
841
      if ((line_buffer[0] == ';') || (line_buffer[0] == '#') || (line_buffer[0] == 0))
784
         continue; // skip comment lines
842
         continue; // skip comment lines
785
 
843
 
786
      // is it a valid section name ?
844
      // is it a valid section name ?
787
      if (swscanf_s (line_buffer, L"[%[^]]", temp_section, WSIZEOF (temp_section)) == 1)
845
      if (swscanf_s (line_buffer, L"[%[^]]", current_section, STRING_MAXSIZE) == 1)
788
      {
846
      {
789
         length = (int) wcslen (temp_section); // get the section string length
847
         length = (int) wcslen (current_section); // get the section string length
790
 
848
 
791
         fieldstart = 0; // let's now strip leading blanks
849
         fieldstart = 0; // let's now strip leading blanks
792
         while ((fieldstart < length) && iswspace (temp_section[fieldstart]))
850
         while ((fieldstart < length) && iswspace (current_section[fieldstart]))
793
            fieldstart++; // ignore any tabs or spaces, going forward from the start
851
            fieldstart++; // ignore any tabs or spaces, going forward from the start
794
 
852
 
795
         fieldstop = length - 1; // let's now strip trailing blanks
853
         fieldstop = length - 1; // let's now strip trailing blanks
796
         while ((fieldstop >= 0) && iswspace (temp_section[fieldstop]))
854
         while ((fieldstop >= 0) && iswspace (current_section[fieldstop]))
797
            fieldstop--; // ignore any tabs or spaces, going backwards from the end
855
            fieldstop--; // ignore any tabs or spaces, going backwards from the end
798
 
856
 
799
         for (i = fieldstart; i <= fieldstop; i++)
857
         for (i = fieldstart; i <= fieldstop; i++)
800
            temp_section[i - fieldstart] = temp_section[i]; // recopy section name w/out spaces
858
            current_section[i - fieldstart] = current_section[i]; // recopy section name w/out spaces
801
         temp_section[i - fieldstart] = 0; // and terminate the string
859
         current_section[i - fieldstart] = 0; // and terminate the string
802
 
860
 
803
         INIFile_WriteEntryAsString (dictionary, temp_section, NULL, NULL); // add to dictionary
861
         INIFile_WriteEntryAsString (dictionary, current_section, NULL, NULL); // add to dictionary
804
      }
862
      }
805
 
863
 
806
      // else is it a valid entry/value pair that is enclosed between quotes?
864
      // else is it a valid entry/value pair that is enclosed between quotes?
807
      else if (swscanf_s (line_buffer, L"%[^=] = \"%[^\"]\"", temp_entry, WSIZEOF (temp_entry), temp_value, WSIZEOF (temp_value)) == 2)
865
      else if (swscanf_s (line_buffer, L"%[^=] = \"%[^\"]\"", current_entry, STRING_MAXSIZE, current_value, STRING_MAXSIZE) == 2)
808
      {
866
      {
809
         length = (int) wcslen (temp_entry); // get the entry string length
867
         length = (int) wcslen (current_entry); // get the entry string length
810
 
868
 
811
         fieldstart = 0; // let's now strip leading blanks
869
         fieldstart = 0; // let's now strip leading blanks
812
         while ((fieldstart < length) && iswspace (temp_entry[fieldstart]))
870
         while ((fieldstart < length) && iswspace (current_entry[fieldstart]))
813
            fieldstart++; // ignore any tabs or spaces, going forward from the start
871
            fieldstart++; // ignore any tabs or spaces, going forward from the start
814
 
872
 
815
         fieldstop = length - 1; // let's now strip trailing blanks
873
         fieldstop = length - 1; // let's now strip trailing blanks
816
         while ((fieldstop >= 0) && iswspace (temp_entry[fieldstop]))
874
         while ((fieldstop >= 0) && iswspace (current_entry[fieldstop]))
817
            fieldstop--; // ignore any tabs or spaces, going backwards from the end
875
            fieldstop--; // ignore any tabs or spaces, going backwards from the end
818
 
876
 
819
         for (i = fieldstart; i <= fieldstop; i++)
877
         for (i = fieldstart; i <= fieldstop; i++)
820
            temp_entry[i - fieldstart] = towlower (temp_entry[i]); // recopy entry name w/out spaces
878
            current_entry[i - fieldstart] = towlower (current_entry[i]); // recopy entry name w/out spaces
821
         temp_entry[i - fieldstart] = 0; // and terminate the string
879
         current_entry[i - fieldstart] = 0; // and terminate the string
822
 
880
 
823
         // when value is enclosed between quotes, DO NOT strip the blanks
881
         // when value is enclosed between quotes, DO NOT strip the blanks
824
 
882
 
825
         // sscanf cannot handle "" or '' as empty value, this is done here
883
         // sscanf cannot handle "" or '' as empty value, this is done here
826
         if ((wcscmp (temp_value, L"\"\"") == 0) || (wcscmp (temp_value, L"''") == 0))
884
         if ((wcscmp (current_value, L"\"\"") == 0) || (wcscmp (current_value, L"''") == 0))
827
            temp_value[0] = 0; // empty string
885
            current_value[0] = 0; // empty string
828
 
886
 
829
         INIFile_WriteEntryAsString (dictionary, temp_section, temp_entry, temp_value); // add to dictionary
887
         INIFile_WriteEntryAsString (dictionary, current_section, current_entry, current_value); // add to dictionary
830
      }
888
      }
831
 
889
 
832
      // else is it a valid entry/value pair without quotes ?
890
      // else is it a valid entry/value pair without quotes ?
833
      else if ((swscanf_s (line_buffer, L"%[^=] = '%[^\']'", temp_entry, WSIZEOF (temp_entry), temp_value, WSIZEOF (temp_value)) == 2)
891
      else if ((swscanf_s (line_buffer, L"%[^=] = '%[^\']'", current_entry, STRING_MAXSIZE, current_value, STRING_MAXSIZE) == 2)
834
               || (swscanf_s (line_buffer, L"%[^=] = %[^;#]", temp_entry, WSIZEOF (temp_entry), temp_value, WSIZEOF (temp_value)) == 2))
892
               || (swscanf_s (line_buffer, L"%[^=] = %[^;#]", current_entry, STRING_MAXSIZE, current_value, STRING_MAXSIZE) == 2))
835
      {
893
      {
836
         length = (int) wcslen (temp_entry); // get the entry string length
894
         length = (int) wcslen (current_entry); // get the entry string length
837
 
895
 
838
         fieldstart = 0; // let's now strip leading blanks
896
         fieldstart = 0; // let's now strip leading blanks
839
         while ((fieldstart < length) && iswspace (temp_entry[fieldstart]))
897
         while ((fieldstart < length) && iswspace (current_entry[fieldstart]))
840
            fieldstart++; // ignore any tabs or spaces, going forward from the start
898
            fieldstart++; // ignore any tabs or spaces, going forward from the start
841
 
899
 
842
         fieldstop = length - 1; // let's now strip trailing blanks
900
         fieldstop = length - 1; // let's now strip trailing blanks
843
         while ((fieldstop >= 0) && iswspace (temp_entry[fieldstop]))
901
         while ((fieldstop >= 0) && iswspace (current_entry[fieldstop]))
844
            fieldstop--; // ignore any tabs or spaces, going backwards from the end
902
            fieldstop--; // ignore any tabs or spaces, going backwards from the end
845
 
903
 
846
         for (i = fieldstart; i <= fieldstop; i++)
904
         for (i = fieldstart; i <= fieldstop; i++)
847
            temp_entry[i - fieldstart] = towlower (temp_entry[i]); // recopy entry name w/out spaces
905
            current_entry[i - fieldstart] = towlower (current_entry[i]); // recopy entry name w/out spaces
848
         temp_entry[i - fieldstart] = 0; // and terminate the string
906
         current_entry[i - fieldstart] = 0; // and terminate the string
849
 
907
 
850
         length = (int) wcslen (temp_value); // get the value string length
908
         length = (int) wcslen (current_value); // get the value string length
851
 
909
 
852
         fieldstart = 0; // let's now strip leading blanks
910
         fieldstart = 0; // let's now strip leading blanks
853
         while ((fieldstart < length) && iswspace (temp_value[fieldstart]))
911
         while ((fieldstart < length) && iswspace (current_value[fieldstart]))
854
            fieldstart++; // ignore any tabs or spaces, going forward from the start
912
            fieldstart++; // ignore any tabs or spaces, going forward from the start
855
 
913
 
856
         fieldstop = length - 1; // let's now strip trailing blanks
914
         fieldstop = length - 1; // let's now strip trailing blanks
857
         while ((fieldstop >= 0) && iswspace (temp_value[fieldstop]))
915
         while ((fieldstop >= 0) && iswspace (current_value[fieldstop]))
858
            fieldstop--; // ignore any tabs or spaces, going backwards from the end
916
            fieldstop--; // ignore any tabs or spaces, going backwards from the end
859
 
917
 
860
         for (i = fieldstart; i <= fieldstop; i++)
918
         for (i = fieldstart; i <= fieldstop; i++)
861
            temp_value[i - fieldstart] = temp_value[i]; // recopy entry name w/out spaces
919
            current_value[i - fieldstart] = current_value[i]; // recopy entry name w/out spaces
862
         temp_value[i - fieldstart] = 0; // and terminate the string
920
         current_value[i - fieldstart] = 0; // and terminate the string
863
 
921
 
864
         // sscanf cannot handle "" or '' as empty value, this is done here
922
         // sscanf cannot handle "" or '' as empty value, this is done here
865
         if ((wcscmp (temp_value, L"\"\"") == 0) || (wcscmp (temp_value, L"''") == 0))
923
         if ((wcscmp (current_value, L"\"\"") == 0) || (wcscmp (current_value, L"''") == 0))
866
            temp_value[0] = 0; // empty string
924
            current_value[0] = 0; // empty string
867
 
925
 
868
         INIFile_WriteEntryAsString (dictionary, temp_section, temp_entry, temp_value); // add to dictionary
926
         INIFile_WriteEntryAsString (dictionary, current_section, current_entry, current_value); // add to dictionary
869
      }
927
      }
870
   }
928
   }
871
 
929
 
872
   fclose (fp); // finished, close the file
930
   fclose (fp); // finished, close the file
-
 
931
   SAFE_free ((void **) &line_buffer); // free the line buffer we allocated at the beginning of the function
-
 
932
   SAFE_free ((void **) &current_value); // free the current value buffer we allocated at the beginning of the function
-
 
933
   SAFE_free ((void **) &current_entry); // free the current entry buffer we allocated at the beginning of the function
-
 
934
   SAFE_free ((void **) &current_section); // free the current section buffer we allocated at the beginning of the function
873
 
935
 
874
   return ((void *) dictionary); // and return
936
   return ((void *) dictionary); // and return a pointer to it
875
}
937
}
876
 
938
 
877
 
939
 
878
unsigned char INIFile_SaveINIFile (const wchar_t *filename, void *ini_data)
940
unsigned char INIFile_SaveINIFile (const wchar_t *filename, void *ini_data)
879
{
941
{
Line 917... Line 979...
917
      if (wcscmp (section_name, INIFile_default_section) == 0)
979
      if (wcscmp (section_name, INIFile_default_section) == 0)
918
         fwprintf (fp, L"\n"); // don't put the default section's name in the INI file
980
         fwprintf (fp, L"\n"); // don't put the default section's name in the INI file
919
      else
981
      else
920
         fwprintf (fp, L"\n[%s]\n", section_name); // dump all other sections into the INI file
982
         fwprintf (fp, L"\n[%s]\n", section_name); // dump all other sections into the INI file
921
 
983
 
922
      // build the section identifier to be used when looking up the dictionary
-
 
923
      swprintf_s (temp_key, WSIZEOF (temp_key), L"%s%c", section_name, INI_SECTION_SEPARATOR);
-
 
924
      length = (int) wcslen (temp_key);
984
      length = (int) wcslen (section_name);
925
 
985
 
926
      // then for each entry in the dictionary...
986
      // then for each entry in the dictionary...
927
      for (entry_index = 0; entry_index < dictionary->entry_count; entry_index++)
987
      for (entry_index = 0; entry_index < dictionary->entry_count; entry_index++)
928
      {
988
      {
929
         entry = &dictionary->entries[entry_index]; // quick access to entry
989
         entry = &dictionary->entries[entry_index]; // quick access to entry
930
 
990
 
931
         if (entry->key[0] == 0)
991
         if (entry->key[0] == 0)
932
            continue; // skip empty slots
992
            continue; // skip empty slots
933
 
993
 
934
         // does this key belong to the section we want ? if so, dump it
994
         // does this key belong to the section we want ? if so, dump it
935
         if (wcsncmp (entry->key, temp_key, length) == 0)
995
         if ((wcsncmp (entry->key, section_name, length) == 0) && (entry->key[length] == INI_SECTION_SEPARATOR))
936
         {
996
         {
937
            // if key starts or ends with a space, enclose it between quotes, else don't
997
            // if key starts or ends with a space, enclose it between quotes, else don't
938
            if ((entry->value[0] != 0)
998
            if ((entry->value[0] != 0)
939
                && (iswspace (entry->value[0]) || iswspace (entry->value[wcslen (entry->value) - 1])))
999
                && (iswspace (entry->value[0]) || iswspace (entry->value[wcslen (entry->value) - 1])))
940
               fwprintf (fp, L"%s = \"%s\"\n", entry->key + length, entry->value);
1000
               fwprintf (fp, L"%s = \"%s\"\n", &entry->key[length + 1], entry->value);
941
            else
1001
            else
942
               fwprintf (fp, L"%s = %s\n", entry->key + length, entry->value);
1002
               fwprintf (fp, L"%s = %s\n", &entry->key[length + 1], entry->value);
943
         }
1003
         }
944
      }
1004
      }
945
   }
1005
   }
946
 
1006
 
947
   fclose (fp); // finished, close the file
1007
   fclose (fp); // finished, close the file