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 |
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 |
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 |
180 | if (value == NULL) |
180 |
|
181 | value = L""; // if a null value was specified, use an empty string |
- | 182 | ||
181 |
|
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 |
|
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, |
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 | // |
212 | // copy the new value |
209 | if (value |
213 | if (value == NULL) |
210 |
|
214 | value = L""; // if a null value was specified, use an empty string |
211 |
|
215 | bufsize = wcslen (value) + 1; |
- | 216 | dictionary->entries[entry_index].value = (wchar_t *) SAFE_malloc (bufsize, sizeof (wchar_t), false); |
|
212 |
|
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 ( |
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, |
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 |
|
538 | size_t length; |
534 |
|
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 ( |
557 | swprintf_s (key, keysize, L"%s%c%s", section, INI_SECTION_SEPARATOR, entry); // compose the key |
547 | 558 | ||
548 | i = |
559 | i = wcslen (key); // get the key string length |
549 | if (i < |
560 | if (i < keysize) |
550 | length = i; |
561 | length = i; |
551 | else |
562 | else |
552 | length = |
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 = |
566 | for (i = wcslen (section) + 1; i < length; i++) |
556 |
|
567 | key[i] = towlower (key[i]); // convert it to lowercase |
557 |
|
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 ( |
573 | wcscpy_s (key, keysize, section); // copy the name into the key |
563 | 574 | ||
564 | value = Dictionary_ReadKey ((dictionary_t *) ini_data, |
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 |
|
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 |
|
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 |
|
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 |
|
658 | size_t length; |
629 |
|
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 ( |
678 | swprintf_s (key, keysize, L"%s%c%s", section, INI_SECTION_SEPARATOR, entry); // compose the key |
643 | 679 | ||
644 | i = |
680 | i = wcslen (key); // get the key string length |
645 | if (i < |
681 | if (i < keysize) |
646 | length = i; |
682 | length = i; |
647 | else |
683 | else |
648 | length = |
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 = |
687 | for (i = wcslen (section) + 1; i < length; i++) |
652 |
|
688 | key[i] = towlower (key[i]); // convert it to lowercase |
653 |
|
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 ( |
694 | wcscpy_s (key, keysize, section); // copy the name into the key |
659 | 695 | ||
660 | Dictionary_WriteKey ((dictionary_t *) ini_data, |
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 |
|
706 | size_t length; |
670 |
|
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 ( |
724 | swprintf_s (key, keysize, L"%s%c%s", section, INI_SECTION_SEPARATOR, entry); // compose the key |
682 | 725 | ||
683 | i = |
726 | i = wcslen (key); // get the key string length |
684 | if (i < |
727 | if (i < keysize) |
685 | length = i; |
728 | length = i; |
686 | else |
729 | else |
687 | length = |
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 = |
733 | for (i = wcslen (section) + 1; i < length; i++) |
691 |
|
734 | key[i] = towlower (key[i]); // convert it to lowercase |
692 |
|
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 ( |
740 | wcscpy_s (key, keysize, section); // copy the name into the key |
698 | 741 | ||
699 | Dictionary_DeleteKey ((dictionary_t *) ini_data, |
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 ( |
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 ( |
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 ( |
776 | if ((wcsncmp (entry->key, section, length) == 0) && (entry->key[length] == INI_SECTION_SEPARATOR)) |
731 | Dictionary_DeleteKey (dictionary, |
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 ( |
815 | wcscpy_s (current_section, STRING_MAXSIZE, INIFile_default_section); |
761 | INIFile_WriteEntryAsString (dictionary, |
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, |
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"[%[^]]", |
845 | if (swscanf_s (line_buffer, L"[%[^]]", current_section, STRING_MAXSIZE) == 1) |
788 | { |
846 | { |
789 | length = (int) wcslen ( |
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 ( |
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 ( |
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 |
|
858 | current_section[i - fieldstart] = current_section[i]; // recopy section name w/out spaces |
801 |
|
859 | current_section[i - fieldstart] = 0; // and terminate the string |
802 | 860 | ||
803 | INIFile_WriteEntryAsString (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"%[^=] = \"%[^\"]\"", |
865 | else if (swscanf_s (line_buffer, L"%[^=] = \"%[^\"]\"", current_entry, STRING_MAXSIZE, current_value, STRING_MAXSIZE) == 2) |
808 | { |
866 | { |
809 | length = (int) wcslen ( |
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 ( |
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 ( |
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 |
|
878 | current_entry[i - fieldstart] = towlower (current_entry[i]); // recopy entry name w/out spaces |
821 |
|
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 ( |
884 | if ((wcscmp (current_value, L"\"\"") == 0) || (wcscmp (current_value, L"''") == 0)) |
827 |
|
885 | current_value[0] = 0; // empty string |
828 | 886 | ||
829 | INIFile_WriteEntryAsString (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"%[^=] = '%[^\']'", |
891 | else if ((swscanf_s (line_buffer, L"%[^=] = '%[^\']'", current_entry, STRING_MAXSIZE, current_value, STRING_MAXSIZE) == 2) |
834 | || (swscanf_s (line_buffer, L"%[^=] = %[^;#]", |
892 | || (swscanf_s (line_buffer, L"%[^=] = %[^;#]", current_entry, STRING_MAXSIZE, current_value, STRING_MAXSIZE) == 2)) |
835 | { |
893 | { |
836 | length = (int) wcslen ( |
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 ( |
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 ( |
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 |
|
905 | current_entry[i - fieldstart] = towlower (current_entry[i]); // recopy entry name w/out spaces |
848 |
|
906 | current_entry[i - fieldstart] = 0; // and terminate the string |
849 | 907 | ||
850 | length = (int) wcslen ( |
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 ( |
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 ( |
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 |
|
919 | current_value[i - fieldstart] = current_value[i]; // recopy entry name w/out spaces |
862 |
|
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 ( |
923 | if ((wcscmp (current_value, L"\"\"") == 0) || (wcscmp (current_value, L"''") == 0)) |
866 |
|
924 | current_value[0] = 0; // empty string |
867 | 925 | ||
868 | INIFile_WriteEntryAsString (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 **) ¤t_value); // free the current value buffer we allocated at the beginning of the function |
|
- | 933 | SAFE_free ((void **) ¤t_entry); // free the current entry buffer we allocated at the beginning of the function |
|
- | 934 | SAFE_free ((void **) ¤t_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 ( |
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, |
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 + |
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 + |
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 |