INI.CPP (73204B)
1 // 2 // Copyright 2020 Electronic Arts Inc. 3 // 4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 5 // software: you can redistribute it and/or modify it under the terms of 6 // the GNU General Public License as published by the Free Software Foundation, 7 // either version 3 of the License, or (at your option) any later version. 8 9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 10 // in the hope that it will be useful, but with permitted additional restrictions 11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 12 // distributed with this program. You should have received a copy of the 13 // GNU General Public License along with permitted additional restrictions 14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection 15 16 /* $Header: /CounterStrike/INI.CPP 1 3/03/97 10:24a Joe_bostic $ */ 17 /*********************************************************************************************** 18 *** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S *** 19 *********************************************************************************************** 20 * * 21 * Project Name : Command & Conquer * 22 * * 23 * File Name : INI.CPP * 24 * * 25 * Programmer : Joe L. Bostic * 26 * * 27 * Start Date : September 10, 1993 * 28 * * 29 * Last Update : November 2, 1996 [JLB] * 30 * * 31 *---------------------------------------------------------------------------------------------* 32 * Functions: * 33 * INIClass::Clear -- Clears out a section (or all sections) of the INI data. * 34 * INIClass::Entry_Count -- Fetches the number of entries in a specified section. * 35 * INIClass::Find_Entry -- Find specified entry within section. * 36 * INIClass::Find_Section -- Find the specified section within the INI data. * 37 * INIClass::Get_Bool -- Fetch a boolean value for the section and entry specified. * 38 * INIClass::Get_Entry -- Get the entry identifier name given ordinal number and section name* 39 * INIClass::Get_Fixed -- Fetch a fixed point number from the section & entry. * 40 * INIClass::Put_Fixed -- Store a fixed point number to the INI database. * 41 * INIClass::Get_Hex -- Fetches integer [hex format] from the section and entry specified. * 42 * INIClass::Get_Int -- Fetch an integer entry from the specified section. * 43 * INIClass::Get_PKey -- Fetch a key from the ini database. * 44 * INIClass::Get_String -- Fetch the value of a particular entry in a specified section. * 45 * INIClass::Get_TextBlock -- Fetch a block of normal text. * 46 * INIClass::Get_UUBlock -- Fetch an encoded block from the section specified. * 47 * INIClass::INISection::Find_Entry -- Finds a specified entry and returns pointer to it. * 48 * INIClass::Load -- Load INI data from the file specified. * 49 * INIClass::Load -- Load the INI data from the data stream (straw). * 50 * INIClass::Put_Bool -- Store a boolean value into the INI database. * 51 * INIClass::Put_Hex -- Store an integer into the INI database, but use a hex format. * 52 * INIClass::Put_Int -- Stores a signed integer into the INI data base. * 53 * INIClass::Put_PKey -- Stores the key to the INI database. * 54 * INIClass::Put_String -- Output a string to the section and entry specified. * 55 * INIClass::Put_TextBlock -- Stores a block of text into an INI section. * 56 * INIClass::Put_UUBlock -- Store a binary encoded data block into the INI database. * 57 * INIClass::Save -- Save the ini data to the file specified. * 58 * INIClass::Save -- Saves the INI data to a pipe stream. * 59 * INIClass::Section_Count -- Counts the number of sections in the INI data. * 60 * INIClass::Strip_Comments -- Strips comments of the specified text line. * 61 * INIClass::~INIClass -- Destructor for INI handler. * 62 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 63 64 #include <string.h> 65 #include <stdlib.h> 66 #include <stddef.h> 67 #include <stdio.h> 68 #include <ctype.h> 69 #include "ini.h" 70 #include "readline.h" 71 #include "xpipe.h" 72 #include "b64pipe.h" 73 #include "xstraw.h" 74 #include "b64straw.h" 75 76 77 #ifdef FIXIT_FAST_LOAD 78 #include "cstraw.h" 79 #endif 80 81 82 83 // Disable the "temporary object used to initialize a non-constant reference" warning. 84 //#pragma warning 665 9 85 86 87 /*********************************************************************************************** 88 * INIClass::~INIClass -- Destructor for INI handler. * 89 * * 90 * This is the destructor for the INI class. It handles deleting all of the allocations * 91 * it might have done. * 92 * * 93 * INPUT: none * 94 * * 95 * OUTPUT: none * 96 * * 97 * WARNINGS: none * 98 * * 99 * HISTORY: * 100 * 07/02/1996 JLB : Created. * 101 *=============================================================================================*/ 102 INIClass::~INIClass(void) 103 { 104 Clear(); 105 } 106 107 108 /*********************************************************************************************** 109 * INIClass::Clear -- Clears out a section (or all sections) of the INI data. * 110 * * 111 * This routine is used to clear out the section specified. If no section is specified, * 112 * then the entire INI data is cleared out. Optionally, this routine can be used to clear * 113 * out just an individual entry in the specified section. * 114 * * 115 * INPUT: section -- Pointer to the section to clear out [pass NULL to clear all]. * 116 * * 117 * entry -- Pointer to optional entry specifier. If this parameter is specified, * 118 * then only this specific entry (if found) will be cleared. Otherwise, * 119 * the entire section specified will be cleared. * 120 * * 121 * OUTPUT: none * 122 * * 123 * WARNINGS: none * 124 * * 125 * HISTORY: * 126 * 07/02/1996 JLB : Created. * 127 * 08/21/1996 JLB : Optionally clears section too. * 128 * 11/02/1996 JLB : Updates the index list. * 129 *=============================================================================================*/ 130 bool INIClass::Clear(char const * section, char const * entry) 131 { 132 if (section == NULL) { 133 SectionList.Delete(); 134 SectionIndex.Clear(); 135 } else { 136 INISection * secptr = Find_Section(section); 137 if (secptr != NULL) { 138 if (entry != NULL) { 139 INIEntry * entptr = secptr->Find_Entry(entry); 140 if (entptr != NULL) { 141 /* 142 ** Remove the entry from the entry index list. 143 */ 144 secptr->EntryIndex.Remove_Index(entptr->Index_ID()); 145 146 delete entptr; 147 } 148 } else { 149 /* 150 ** Remove this section index from the section index list. 151 */ 152 SectionIndex.Remove_Index(secptr->Index_ID()); 153 154 delete secptr; 155 } 156 } 157 } 158 return(true); 159 } 160 161 162 /*********************************************************************************************** 163 * INIClass::Load -- Load INI data from the file specified. * 164 * * 165 * Use this routine to load the INI class with the data from the specified file. * 166 * * 167 * INPUT: file -- Reference to the file that will be used to fill up this INI manager. * 168 * * 169 * OUTPUT: bool; Was the file loaded successfully? * 170 * * 171 * WARNINGS: This routine allocates memory. * 172 * * 173 * HISTORY: * 174 * 07/02/1996 JLB : Created. * 175 *=============================================================================================*/ 176 bool INIClass::Load(FileClass & file) 177 { 178 return(Load(FileStraw(file))); 179 } 180 181 182 /*********************************************************************************************** 183 * INIClass::Load -- Load the INI data from the data stream (straw). * 184 * * 185 * This will fetch data from the straw and build an INI database from it. * 186 * * 187 * INPUT: straw -- The straw that the data will be provided from. * 188 * * 189 * OUTPUT: bool; Was the database loaded ok? * 190 * * 191 * WARNINGS: none * 192 * * 193 * HISTORY: * 194 * 07/10/1996 JLB : Created. * 195 *=============================================================================================*/ 196 #ifdef FIXIT_FAST_LOAD 197 bool INIClass::Load(Straw & ffile) 198 #else 199 bool INIClass::Load(Straw & file) 200 #endif 201 { 202 bool end_of_file = false; 203 char buffer[MAX_LINE_LENGTH]; 204 205 #ifdef FIXIT_FAST_LOAD 206 CacheStraw file; 207 file.Get_From(ffile); 208 #endif 209 210 /* 211 ** Prescan until the first section is found. 212 */ 213 while (!end_of_file) { 214 Read_Line(file, buffer, sizeof(buffer), end_of_file); 215 if (end_of_file) return(false); 216 if (buffer[0] == '[' && strchr(buffer, ']') != NULL) break; 217 } 218 219 /* 220 ** Process a section. The buffer is prefilled with the section name line. 221 */ 222 while (!end_of_file) { 223 224 buffer[0] = ' '; 225 char * ptr = strchr(buffer, ']'); 226 if (ptr) *ptr = '\0'; 227 strtrim(buffer); 228 INISection * secptr = new INISection(strdup(buffer)); 229 if (secptr == NULL) { 230 Clear(); 231 return(false); 232 } 233 234 /* 235 ** Read in the entries of this section. 236 */ 237 while (!end_of_file) { 238 239 /* 240 ** If this line is the start of another section, then bail out 241 ** of the entry loop and let the outer section loop take 242 ** care of it. 243 */ 244 int len = Read_Line(file, buffer, sizeof(buffer), end_of_file); 245 if (buffer[0] == '[' && strchr(buffer, ']') != NULL) break; 246 247 /* 248 ** Determine if this line is a comment or blank line. Throw it out if it is. 249 */ 250 Strip_Comments(buffer); 251 if (len == 0 || buffer[0] == ';' || buffer[0] == '=') continue; 252 253 /* 254 ** The line isn't an obvious comment. Make sure that there is the "=" character 255 ** at an appropriate spot. 256 */ 257 char * divider = strchr(buffer, '='); 258 if (!divider) continue; 259 260 /* 261 ** Split the line into entry and value sections. Be sure to catch the 262 ** "=foobar" and "foobar=" cases. These lines are ignored. 263 */ 264 *divider++ = '\0'; 265 strtrim(buffer); 266 if (!strlen(buffer)) continue; 267 268 strtrim(divider); 269 if (!strlen(divider)) continue; 270 271 INIEntry * entryptr = new INIEntry(strdup(buffer), strdup(divider)); 272 if (entryptr == NULL) { 273 delete secptr; 274 Clear(); 275 return(false); 276 } 277 278 secptr->EntryIndex.Add_Index(entryptr->Index_ID(), entryptr); 279 secptr->EntryList.Add_Tail(entryptr); 280 } 281 282 /* 283 ** All the entries for this section have been parsed. If this section is blank, then 284 ** don't bother storing it. 285 */ 286 if (secptr->EntryList.Is_Empty()) { 287 delete secptr; 288 } else { 289 SectionIndex.Add_Index(secptr->Index_ID(), secptr); 290 SectionList.Add_Tail(secptr); 291 } 292 } 293 return(true); 294 } 295 296 297 /*********************************************************************************************** 298 * INIClass::Save -- Save the ini data to the file specified. * 299 * * 300 * Use this routine to save the ini data to the file specified. All existing data in the * 301 * file, if it was present, is replaced. * 302 * * 303 * INPUT: file -- Reference to the file to write the INI data to. * 304 * * 305 * OUTPUT: bool; Was the data written to the file? * 306 * * 307 * WARNINGS: none * 308 * * 309 * HISTORY: * 310 * 07/02/1996 JLB : Created. * 311 *=============================================================================================*/ 312 int INIClass::Save(FileClass & file) const 313 { 314 return(Save(FilePipe(file))); 315 } 316 317 318 /*********************************************************************************************** 319 * INIClass::Save -- Saves the INI data to a pipe stream. * 320 * * 321 * This routine will output the data of the INI file to a pipe stream. * 322 * * 323 * INPUT: pipe -- Reference to the pipe stream to pump the INI image to. * 324 * * 325 * OUTPUT: Returns with the number of bytes output to the pipe. * 326 * * 327 * WARNINGS: none * 328 * * 329 * HISTORY: * 330 * 07/02/1996 JLB : Created. * 331 *=============================================================================================*/ 332 int INIClass::Save(Pipe & pipe) const 333 { 334 int total = 0; 335 336 INISection * secptr = SectionList.First(); 337 while (secptr && secptr->Is_Valid()) { 338 339 /* 340 ** Output the section identifier. 341 */ 342 total += pipe.Put("[", 1); 343 total += pipe.Put(secptr->Section, strlen(secptr->Section)); 344 total += pipe.Put("]", 1); 345 total += pipe.Put("\r\n", strlen("\r\n")); 346 347 /* 348 ** Output all the entries and values in this section. 349 */ 350 INIEntry * entryptr = secptr->EntryList.First(); 351 while (entryptr && entryptr->Is_Valid()) { 352 total += pipe.Put(entryptr->Entry, strlen(entryptr->Entry)); 353 total += pipe.Put("=", 1); 354 total += pipe.Put(entryptr->Value, strlen(entryptr->Value)); 355 total += pipe.Put("\r\n", strlen("\r\n")); 356 357 entryptr = entryptr->Next(); 358 } 359 360 /* 361 ** After the last entry in this section, output an extra 362 ** blank line for readability purposes. 363 */ 364 total += pipe.Put("\r\n", strlen("\r\n")); 365 366 secptr = secptr->Next(); 367 } 368 total += pipe.End(); 369 370 return(total); 371 } 372 373 374 /*********************************************************************************************** 375 * INIClass::Find_Section -- Find the specified section within the INI data. * 376 * * 377 * This routine will scan through the INI data looking for the section specified. If the * 378 * section could be found, then a pointer to the section control data is returned. * 379 * * 380 * INPUT: section -- The name of the section to search for. Don't enclose the name in * 381 * brackets. Case is NOT sensitive in the search. * 382 * * 383 * OUTPUT: Returns with a pointer to the INI section control structure if the section was * 384 * found. Otherwise, NULL is returned. * 385 * * 386 * WARNINGS: none * 387 * * 388 * HISTORY: * 389 * 07/02/1996 JLB : Created. * 390 * 11/02/1996 JLB : Uses index manager. * 391 *=============================================================================================*/ 392 INIClass::INISection * INIClass::Find_Section(char const * section) const 393 { 394 if (section != NULL) { 395 396 long crc = CRCEngine()(section, strlen(section)); 397 398 if (SectionIndex.Is_Present(crc)) { 399 return(SectionIndex.Fetch_Index(crc)); 400 } 401 } 402 return(NULL); 403 } 404 405 406 /*********************************************************************************************** 407 * INIClass::Section_Count -- Counts the number of sections in the INI data. * 408 * * 409 * This routine will scan through all the sections in the INI data and return a count * 410 * of the number it found. * 411 * * 412 * INPUT: none * 413 * * 414 * OUTPUT: Returns with the number of sections recorded in the INI data. * 415 * * 416 * WARNINGS: none * 417 * * 418 * HISTORY: * 419 * 07/02/1996 JLB : Created. * 420 * 11/02/1996 JLB : Uses index manager. * 421 *=============================================================================================*/ 422 int INIClass::Section_Count(void) const 423 { 424 return(SectionIndex.Count()); 425 } 426 427 428 /*********************************************************************************************** 429 * INIClass::Entry_Count -- Fetches the number of entries in a specified section. * 430 * * 431 * This routine will examine the section specified and return with the number of entries * 432 * associated with it. * 433 * * 434 * INPUT: section -- Pointer to the section that will be examined. * 435 * * 436 * OUTPUT: Returns with the number entries in the specified section. * 437 * * 438 * WARNINGS: none * 439 * * 440 * HISTORY: * 441 * 07/02/1996 JLB : Created. * 442 * 11/02/1996 JLB : Uses index manager. * 443 *=============================================================================================*/ 444 int INIClass::Entry_Count(char const * section) const 445 { 446 INISection * secptr = Find_Section(section); 447 if (secptr != NULL) { 448 return(secptr->EntryIndex.Count()); 449 } 450 return(0); 451 } 452 453 454 /*********************************************************************************************** 455 * INIClass::Find_Entry -- Find specified entry within section. * 456 * * 457 * This support routine will find the specified entry in the specified section. If found, * 458 * a pointer to the entry control structure will be returned. * 459 * * 460 * INPUT: section -- Pointer to the section name to search under. * 461 * * 462 * entry -- Pointer to the entry name to search for. * 463 * * 464 * OUTPUT: If the entry was found, then a pointer to the entry control structure will be * 465 * returned. Otherwise, NULL will be returned. * 466 * * 467 * WARNINGS: none * 468 * * 469 * HISTORY: * 470 * 07/02/1996 JLB : Created. * 471 *=============================================================================================*/ 472 INIClass::INIEntry * INIClass::Find_Entry(char const * section, char const * entry) const 473 { 474 INISection * secptr = Find_Section(section); 475 if (secptr != NULL) { 476 return(secptr->Find_Entry(entry)); 477 } 478 return(NULL); 479 } 480 481 482 /*********************************************************************************************** 483 * INIClass::Get_Entry -- Get the entry identifier name given ordinal number and section name. * 484 * * 485 * This will return the identifier name for the entry under the section specified. The * 486 * ordinal number specified is used to determine which entry to retrieve. The entry * 487 * identifier is the text that appears to the left of the "=" character. * 488 * * 489 * INPUT: section -- The section to use. * 490 * * 491 * index -- The ordinal number to use when fetching an entry name. * 492 * * 493 * OUTPUT: Returns with a pointer to the entry name. * 494 * * 495 * WARNINGS: none * 496 * * 497 * HISTORY: * 498 * 07/02/1996 JLB : Created. * 499 *=============================================================================================*/ 500 char const * INIClass::Get_Entry(char const * section, int index) const 501 { 502 INISection * secptr = Find_Section(section); 503 504 if (secptr != NULL && index < secptr->EntryIndex.Count()) { 505 INIEntry * entryptr = secptr->EntryList.First(); 506 507 while (entryptr != NULL && entryptr->Is_Valid()) { 508 if (index == 0) return(entryptr->Entry); 509 index--; 510 entryptr = entryptr->Next(); 511 } 512 } 513 return(NULL); 514 } 515 516 517 /*********************************************************************************************** 518 * INIClass::Put_UUBlock -- Store a binary encoded data block into the INI database. * 519 * * 520 * Use this routine to store an arbitrary length binary block of data into the INI database.* 521 * This routine will covert the data into displayable form and then break it into lines * 522 * that are stored in sequence to the section. A section used to store data in this * 523 * fashion can not be used for any other entries. * 524 * * 525 * INPUT: section -- The section identifier to place the data into. * 526 * * 527 * block -- Pointer to the block of binary data to store. * 528 * * 529 * len -- The length of the binary data. * 530 * * 531 * OUTPUT: bool; Was the data stored to the database? * 532 * * 533 * WARNINGS: none * 534 * * 535 * HISTORY: * 536 * 07/03/1996 JLB : Created. * 537 *=============================================================================================*/ 538 bool INIClass::Put_UUBlock(char const * section, void const * block, int len) 539 { 540 if (section == NULL || block == NULL || len < 1) return(false); 541 542 Clear(section); 543 544 BufferStraw straw(block, len); 545 Base64Straw bstraw(Base64Straw::ENCODE); 546 bstraw.Get_From(straw); 547 548 int counter = 1; 549 550 for (;;) { 551 char buffer[71]; 552 char sbuffer[32]; 553 554 int length = bstraw.Get(buffer, sizeof(buffer)-1); 555 buffer[length] = '\0'; 556 if (length == 0) break; 557 558 sprintf(sbuffer, "%d", counter); 559 Put_String(section, sbuffer, buffer); 560 counter++; 561 } 562 return(true); 563 } 564 565 566 /*********************************************************************************************** 567 * INIClass::Get_UUBlock -- Fetch an encoded block from the section specified. * 568 * * 569 * This routine will take all the entries in the specified section and decompose them into * 570 * a binary block of data that will be stored into the buffer specified. By using this * 571 * routine [and the Put_UUBLock counterpart], arbitrary blocks of binary data may be * 572 * stored in the INI file. A section processed by this routine can contain no other * 573 * entries than those put there by a previous call to Put_UUBlock. * 574 * * 575 * INPUT: section -- The section name to process. * 576 * * 577 * block -- Pointer to the buffer that will hold the retrieved data. * 578 * * 579 * len -- The length of the buffer. The retrieved data will not fill past this * 580 * limit. * 581 * * 582 * OUTPUT: Returns with the number of bytes decoded into the buffer specified. * 583 * * 584 * WARNINGS: If the number of bytes retrieved exactly matches the length of the buffer * 585 * specified, then you might have a condition of buffer "overflow". * 586 * * 587 * HISTORY: * 588 * 07/02/1996 JLB : Created. * 589 *=============================================================================================*/ 590 int INIClass::Get_UUBlock(char const * section, void * block, int len) const 591 { 592 if (section == NULL) return(0); 593 594 Base64Pipe b64pipe(Base64Pipe::DECODE); 595 BufferPipe bpipe(block, len); 596 597 b64pipe.Put_To(&bpipe); 598 599 int total = 0; 600 int counter = Entry_Count(section); 601 for (int index = 0; index < counter; index++) { 602 char buffer[128]; 603 604 int length = Get_String(section, Get_Entry(section, index), "=", buffer, sizeof(buffer)); 605 int outcount = b64pipe.Put(buffer, length); 606 total += outcount; 607 } 608 total += b64pipe.End(); 609 return(total); 610 } 611 612 613 /*********************************************************************************************** 614 * INIClass::Put_TextBlock -- Stores a block of text into an INI section. * 615 * * 616 * This routine will take an arbitrarily long block of text and store it into the INI * 617 * database. The text is broken up into lines and each line is then stored as a numbered * 618 * entry in the specified section. A section used to store text in this way can not be used * 619 * to hold any other entries. The text is presumed to contain space characters scattered * 620 * throughout it and that one space between words and sentences is natural. * 621 * * 622 * INPUT: section -- The section to place the text block into. * 623 * * 624 * text -- Pointer to a null terminated text string that holds the block of * 625 * text. The length can be arbitrary. * 626 * * 627 * OUTPUT: bool; Was the text block placed into the database? * 628 * * 629 * WARNINGS: none * 630 * * 631 * HISTORY: * 632 * 07/03/1996 JLB : Created. * 633 *=============================================================================================*/ 634 bool INIClass::Put_TextBlock(char const * section, char const * text) 635 { 636 if (section == NULL) return(false); 637 638 Clear(section); 639 640 int index = 1; 641 while (text != NULL && *text != NULL) { 642 643 char buffer[128]; 644 645 strncpy(buffer, text, 75); 646 buffer[75] = '\0'; 647 648 char b[32]; 649 sprintf(b, "%d", index); 650 651 /* 652 ** Scan backward looking for a good break position. 653 */ 654 int count = strlen(buffer); 655 if (count > 0) { 656 if (count >= 75) { 657 while (count) { 658 char c = buffer[count]; 659 660 if (isspace(c)) break; 661 count--; 662 } 663 664 if (count == 0) { 665 break; 666 } else { 667 buffer[count] = '\0'; 668 } 669 } 670 671 strtrim(buffer); 672 Put_String(section, b, buffer); 673 index++; 674 text = ((char *)text) + count; 675 } else { 676 break; 677 } 678 } 679 return(true); 680 } 681 682 683 /*********************************************************************************************** 684 * INIClass::Get_TextBlock -- Fetch a block of normal text. * 685 * * 686 * This will take all entries in the specified section and format them into a block of * 687 * normalized text. That is, text with single spaces between each concatenated line. All * 688 * entries in the specified section are processed by this routine. Use Put_TextBlock to * 689 * build the entries in the section. * 690 * * 691 * INPUT: section -- The section name to process. * 692 * * 693 * buffer -- Pointer to the buffer that will hold the complete text. * 694 * * 695 * len -- The length of the buffer specified. The text will, at most, fill this * 696 * buffer with the last character being forced to null. * 697 * * 698 * OUTPUT: Returns with the number of characters placed into the buffer. The trailing null * 699 * is not counted. * 700 * * 701 * WARNINGS: none * 702 * * 703 * HISTORY: * 704 * 07/02/1996 JLB : Created. * 705 *=============================================================================================*/ 706 int INIClass::Get_TextBlock(char const * section, char * buffer, int len) const 707 { 708 if (len <= 0) return(0); 709 710 buffer[0] = '\0'; 711 if (len <= 1) return(0); 712 713 int elen = Entry_Count(section); 714 int total = 0; 715 for (int index = 0; index < elen; index++) { 716 717 /* 718 ** Add spacers between lines of fetched text. 719 */ 720 if (index > 0) { 721 *buffer++ = ' '; 722 len--; 723 total++; 724 } 725 726 Get_String(section, Get_Entry(section, index), "", buffer, len); 727 728 int partial = strlen(buffer); 729 total += partial; 730 buffer += partial; 731 len -= partial; 732 if (len <= 1) break; 733 } 734 return(total); 735 } 736 737 738 /*********************************************************************************************** 739 * INIClass::Put_Int -- Stores a signed integer into the INI data base. * 740 * * 741 * Use this routine to store an integer value into the section and entry specified. * 742 * * 743 * INPUT: section -- The identifier for the section that the entry will be placed in. * 744 * * 745 * entry -- The entry identifier used for the integer number. * 746 * * 747 * number -- The integer number to store in the database. * 748 * * 749 * format -- The format to store the integer. The format is generally only a * 750 * cosmetic affect. The Get_Int operation will interpret the value the * 751 * same regardless of what format was used to store the integer. * 752 * * 753 * 0 : plain decimal digit * 754 * 1 : hexadecimal digit (trailing "h") * 755 * 2 : hexadecimal digit (leading "$") * 756 * * 757 * OUTPUT: bool; Was the number stored? * 758 * * 759 * WARNINGS: none * 760 * * 761 * HISTORY: * 762 * 07/03/1996 JLB : Created. * 763 * 07/10/1996 JLB : Handles multiple integer formats. * 764 *=============================================================================================*/ 765 bool INIClass::Put_Int(char const * section, char const * entry, int number, int format) 766 { 767 char buffer[MAX_LINE_LENGTH]; 768 769 switch (format) { 770 default: 771 case 0: 772 sprintf(buffer, "%d", number); 773 break; 774 775 case 1: 776 sprintf(buffer, "%Xh", number); 777 break; 778 779 case 2: 780 sprintf(buffer, "$%X", number); 781 break; 782 } 783 return(Put_String(section, entry, buffer)); 784 } 785 786 787 /*********************************************************************************************** 788 * INIClass::Get_Int -- Fetch an integer entry from the specified section. * 789 * * 790 * This routine will fetch an integer value from the entry and section specified. If no * 791 * entry could be found, then the default value will be returned instead. * 792 * * 793 * INPUT: section -- The section name to search under. * 794 * * 795 * entry -- The entry name to search for. * 796 * * 797 * defvalue -- The default value to use if the specified entry could not be found. * 798 * * 799 * OUTPUT: Returns with the integer value specified in the INI database or else returns the * 800 * default value. * 801 * * 802 * WARNINGS: none * 803 * * 804 * HISTORY: * 805 * 07/02/1996 JLB : Created. * 806 * 07/10/1996 JLB : Handles multiple integer formats. * 807 *=============================================================================================*/ 808 int INIClass::Get_Int(char const * section, char const * entry, int defvalue) const 809 { 810 /* 811 ** Verify that the parameters are nominally correct. 812 */ 813 if (section == NULL || entry == NULL) return(defvalue); 814 815 INIEntry * entryptr = Find_Entry(section, entry); 816 if (entryptr && entryptr->Value != NULL) { 817 818 if (*entryptr->Value == '$') { 819 sscanf(entryptr->Value, "$%x", &defvalue); 820 } else { 821 if (tolower(entryptr->Value[strlen(entryptr->Value)-1]) == 'h') { 822 sscanf(entryptr->Value, "%xh", &defvalue); 823 } else { 824 defvalue = atoi(entryptr->Value); 825 } 826 } 827 } 828 return(defvalue); 829 } 830 831 832 /*********************************************************************************************** 833 * INIClass::Put_Hex -- Store an integer into the INI database, but use a hex format. * 834 * * 835 * This routine is similar to the Put_Int routine, but the number is stored as a hexadecimal* 836 * number. * 837 * * 838 * INPUT: section -- The identifier for the section that the entry will be placed in. * 839 * * 840 * entry -- The entry identifier to tag to the integer number specified. * 841 * * 842 * number -- The number to assign the the specified entry and placed in the * 843 * specified section. * 844 * * 845 * OUTPUT: bool; Was the number placed into the INI database? * 846 * * 847 * WARNINGS: none * 848 * * 849 * HISTORY: * 850 * 07/03/1996 JLB : Created. * 851 *=============================================================================================*/ 852 bool INIClass::Put_Hex(char const * section, char const * entry, int number) 853 { 854 char buffer[MAX_LINE_LENGTH]; 855 856 sprintf(buffer, "%X", number); 857 return(Put_String(section, entry, buffer)); 858 } 859 860 861 /*********************************************************************************************** 862 * INIClass::Get_Hex -- Fetches integer [hex format] from the section and entry specified. * 863 * * 864 * This routine will search under the section specified, looking for a matching entry. The * 865 * value is interpreted as a hexadecimal number and then returned. If no entry could be * 866 * found, then the default value is returned instead. * 867 * * 868 * INPUT: section -- The section identifier to search under. * 869 * * 870 * entry -- The entry identifier to search for. * 871 * * 872 * defvalue -- The default value to use if the entry could not be located. * 873 * * 874 * OUTPUT: Returns with the integer value from the specified section and entry. If no entry * 875 * could be found, then the default value will be returned instead. * 876 * * 877 * WARNINGS: none * 878 * * 879 * HISTORY: * 880 * 07/02/1996 JLB : Created. * 881 *=============================================================================================*/ 882 int INIClass::Get_Hex(char const * section, char const * entry, int defvalue) const 883 { 884 /* 885 ** Verify that the parameters are nominally correct. 886 */ 887 if (section == NULL || entry == NULL) return(defvalue); 888 889 INIEntry * entryptr = Find_Entry(section, entry); 890 if (entryptr && entryptr->Value != NULL) { 891 sscanf(entryptr->Value, "%x", &defvalue); 892 } 893 return(defvalue); 894 } 895 896 897 /*********************************************************************************************** 898 * INIClass::Put_String -- Output a string to the section and entry specified. * 899 * * 900 * This routine will put an arbitrary string to the section and entry specified. Any * 901 * previous matching entry will be replaced. * 902 * * 903 * INPUT: section -- The section identifier to place the string under. * 904 * * 905 * entry -- The entry identifier to identify this string [placed under the section]* 906 * * 907 * string -- Pointer to the string to assign to this entry. * 908 * * 909 * OUTPUT: bool; Was the entry assigned without error? * 910 * * 911 * WARNINGS: none * 912 * * 913 * HISTORY: * 914 * 07/02/1996 JLB : Created. * 915 * 11/02/1996 JLB : Uses index handler. * 916 *=============================================================================================*/ 917 bool INIClass::Put_String(char const * section, char const * entry, char const * string) 918 { 919 if (section == NULL || entry == NULL) return(false); 920 921 INISection * secptr = Find_Section(section); 922 923 if (secptr == NULL) { 924 secptr = new INISection(strdup(section)); 925 if (secptr == NULL) return(false); 926 SectionList.Add_Tail(secptr); 927 SectionIndex.Add_Index(secptr->Index_ID(), secptr); 928 } 929 930 /* 931 ** Remove the old entry if found. 932 */ 933 INIEntry * entryptr = secptr->Find_Entry(entry); 934 if (entryptr != NULL) { 935 secptr->EntryIndex.Remove_Index(entryptr->Index_ID()); 936 delete entryptr; 937 } 938 939 /* 940 ** Create and add the new entry. 941 */ 942 if (string != NULL && strlen(string) > 0) { 943 entryptr = new INIEntry(strdup(entry), strdup(string)); 944 945 if (entryptr == NULL) { 946 return(false); 947 } 948 secptr->EntryList.Add_Tail(entryptr); 949 secptr->EntryIndex.Add_Index(entryptr->Index_ID(), entryptr); 950 } 951 return(true); 952 } 953 954 955 /*********************************************************************************************** 956 * INIClass::Get_String -- Fetch the value of a particular entry in a specified section. * 957 * * 958 * This will retrieve the entire text to the right of the "=" character. The text is * 959 * found by finding a matching entry in the section specified. If no matching entry could * 960 * be found, then the default value will be stored in the output string buffer. * 961 * * 962 * INPUT: section -- Pointer to the section name to search under. * 963 * * 964 * entry -- The entry identifier to search for. * 965 * * 966 * defvalue -- If no entry could be found, then this text will be returned. * 967 * * 968 * buffer -- Output buffer to store the retrieved string into. * 969 * * 970 * size -- The size of the output buffer. The maximum string length that could * 971 * be retrieved will be one less than this length. This is due to the * 972 * forced trailing zero added to the end of the string. * 973 * * 974 * OUTPUT: Returns with the length of the string retrieved. * 975 * * 976 * WARNINGS: none * 977 * * 978 * HISTORY: * 979 * 07/02/1996 JLB : Created. * 980 *=============================================================================================*/ 981 int INIClass::Get_String(char const * section, char const * entry, char const * defvalue, char * buffer, int size) const 982 { 983 /* 984 ** Verify that the parameters are nominally legal. 985 */ 986 if (section == NULL || entry == NULL) { 987 if (buffer != NULL && size > 0) { 988 buffer[0] = '\0'; 989 } 990 return(0); 991 } 992 993 /* 994 ** Fetch the entry string if it is present. If not, then the normal default 995 ** value will be used as the entry value. 996 */ 997 INIEntry * entryptr = Find_Entry(section, entry); 998 if (entryptr) { 999 if (entryptr->Value) { 1000 defvalue = entryptr->Value; 1001 } 1002 } 1003 1004 /* 1005 ** Fill in the buffer with the entry value and return with the length of the string. 1006 */ 1007 if (buffer == NULL || !size) { 1008 return(0); 1009 } else if (defvalue == NULL) { 1010 buffer[0] = '\0'; 1011 return(0); 1012 } else if (buffer == defvalue) { 1013 return(strlen(buffer)); 1014 } else { 1015 strncpy(buffer, defvalue, size); 1016 buffer[size-1] = '\0'; 1017 strtrim(buffer); 1018 return(strlen(buffer)); 1019 } 1020 } 1021 1022 1023 /*********************************************************************************************** 1024 * INIClass::Put_Bool -- Store a boolean value into the INI database. * 1025 * * 1026 * Use this routine to place a boolean value into the INI database. The boolean value will * 1027 * be stored as "yes" or "no". * 1028 * * 1029 * INPUT: section -- The section to place the entry and boolean value into. * 1030 * * 1031 * entry -- The entry identifier to tag to the boolean value. * 1032 * * 1033 * value -- The boolean value to place into the database. * 1034 * * 1035 * OUTPUT: bool; Was the boolean value placed into the database? * 1036 * * 1037 * WARNINGS: none * 1038 * * 1039 * HISTORY: * 1040 * 07/03/1996 JLB : Created. * 1041 *=============================================================================================*/ 1042 bool INIClass::Put_Bool(char const * section, char const * entry, bool value) 1043 { 1044 if (value) { 1045 return(Put_String(section, entry, "yes")); 1046 } else { 1047 return(Put_String(section, entry, "no")); 1048 } 1049 } 1050 1051 1052 /*********************************************************************************************** 1053 * INIClass::Get_Bool -- Fetch a boolean value for the section and entry specified. * 1054 * * 1055 * This routine will search under the section specified, looking for a matching entry. If * 1056 * one is found, the value is interpreted as a boolean value and then returned. In the case * 1057 * of no matching entry, the default value will be returned instead. The boolean value * 1058 * is interpreted using the standard boolean conventions. e.g., "Yes", "Y", "1", "True", * 1059 * "T" are all consider to be a TRUE boolean value. * 1060 * * 1061 * INPUT: section -- The section to search under. * 1062 * * 1063 * entry -- The entry to search for. * 1064 * * 1065 * defvalue -- The default value to use if no matching entry could be located. * 1066 * * 1067 * OUTPUT: Returns with the boolean value of the specified section and entry. If no match * 1068 * then the default boolean value is returned. * 1069 * * 1070 * WARNINGS: none * 1071 * * 1072 * HISTORY: * 1073 * 07/02/1996 JLB : Created. * 1074 *=============================================================================================*/ 1075 bool INIClass::Get_Bool(char const * section, char const * entry, bool defvalue) const 1076 { 1077 /* 1078 ** Verify that the parameters are nominally correct. 1079 */ 1080 if (section == NULL || entry == NULL) return(defvalue); 1081 1082 INIEntry * entryptr = Find_Entry(section, entry); 1083 if (entryptr && entryptr->Value != NULL) { 1084 switch (toupper(*entryptr->Value)) { 1085 case 'Y': 1086 case 'T': 1087 case '1': 1088 return(true); 1089 1090 case 'N': 1091 case 'F': 1092 case '0': 1093 return(false); 1094 } 1095 } 1096 return(defvalue); 1097 } 1098 1099 1100 /*********************************************************************************************** 1101 * INIClass::INISection::Find_Entry -- Finds a specified entry and returns pointer to it. * 1102 * * 1103 * This routine scans the supplied entry for the section specified. This is used for * 1104 * internal database maintenance. * 1105 * * 1106 * INPUT: entry -- The entry to scan for. * 1107 * * 1108 * OUTPUT: Returns with a pointer to the entry control structure if the entry was found. * 1109 * Otherwise it returns NULL. * 1110 * * 1111 * WARNINGS: none * 1112 * * 1113 * HISTORY: * 1114 * 07/03/1996 JLB : Created. * 1115 * 11/02/1996 JLB : Uses index handler. * 1116 *=============================================================================================*/ 1117 INIClass::INIEntry * INIClass::INISection::Find_Entry(char const * entry) const 1118 { 1119 if (entry != NULL) { 1120 int crc = CRCEngine()(entry, strlen(entry)); 1121 if (EntryIndex.Is_Present(crc)) { 1122 return(EntryIndex.Fetch_Index(crc)); 1123 } 1124 } 1125 return(NULL); 1126 } 1127 1128 1129 /*********************************************************************************************** 1130 * INIClass::Put_PKey -- Stores the key to the INI database. * 1131 * * 1132 * The key stored to the database will have both the exponent and modulus portions saved. * 1133 * Since the fast key only requires the modulus, it is only necessary to save the slow * 1134 * key to the database. However, storing the slow key stores the information necessary to * 1135 * generate the fast and slow keys. Because public key encryption requires one key to be * 1136 * completely secure, only store the fast key in situations where the INI database will * 1137 * be made public. * 1138 * * 1139 * INPUT: key -- The key to store the INI database. * 1140 * * 1141 * OUTPUT: bool; Was the key stored to the database? * 1142 * * 1143 * WARNINGS: Store the fast key for public INI database availability. Store the slow key if * 1144 * the INI database is secure. * 1145 * * 1146 * HISTORY: * 1147 * 07/08/1996 JLB : Created. * 1148 *=============================================================================================*/ 1149 bool INIClass::Put_PKey(PKey const & key) 1150 { 1151 char buffer[512]; 1152 1153 int len = key.Encode_Modulus(buffer); 1154 Put_UUBlock("PublicKey", buffer, len); 1155 1156 len = key.Encode_Exponent(buffer); 1157 Put_UUBlock("PrivateKey", buffer, len); 1158 return(true); 1159 } 1160 1161 1162 /*********************************************************************************************** 1163 * INIClass::Get_PKey -- Fetch a key from the ini database. * 1164 * * 1165 * This routine will fetch the key from the INI database. The key fetched is controlled by * 1166 * the parameter. There are two choices of key -- the fast or slow key. * 1167 * * 1168 * INPUT: fast -- Should the fast key be retrieved? The fast key has the advantage of * 1169 * requiring only the modulus value. * 1170 * * 1171 * OUTPUT: Returns with the key retrieved. * 1172 * * 1173 * WARNINGS: none * 1174 * * 1175 * HISTORY: * 1176 * 07/08/1996 JLB : Created. * 1177 *=============================================================================================*/ 1178 PKey INIClass::Get_PKey(bool fast) const 1179 { 1180 PKey key; 1181 char buffer[512]; 1182 1183 /* 1184 ** When retrieving the fast key, the exponent is a known constant. Don't parse the 1185 ** exponent from the database. 1186 */ 1187 if (fast) { 1188 BigInt exp = PKey::Fast_Exponent(); 1189 exp.DEREncode((unsigned char *)buffer); 1190 key.Decode_Exponent(buffer); 1191 } else { 1192 Get_UUBlock("PrivateKey", buffer, sizeof(buffer)); 1193 key.Decode_Exponent(buffer); 1194 } 1195 1196 Get_UUBlock("PublicKey", buffer, sizeof(buffer)); 1197 key.Decode_Modulus(buffer); 1198 1199 return(key); 1200 } 1201 1202 1203 /*********************************************************************************************** 1204 * INIClass::Get_Fixed -- Fetch a fixed point number from the section & entry. * 1205 * * 1206 * This routine will examine the section and entry specified and interpret the value * 1207 * as if it were a fixed point number. The format of the fixed point number can be * 1208 * percentage (e.g. 100%) or a floating point number (e.g., 1.7). * 1209 * * 1210 * INPUT: section -- Pointer to the section identifier to look under. * 1211 * * 1212 * entry -- Pointer to the entry identifier to examine. * 1213 * * 1214 * defvalue -- If the section and entry could not be found, then this value will * 1215 * be returned. * 1216 * * 1217 * OUTPUT: Returns with the fixed point number that occurs at the section and entry * 1218 * specified. If it could not be found, then the default value is returned. * 1219 * * 1220 * WARNINGS: none * 1221 * * 1222 * HISTORY: * 1223 * 07/03/1996 JLB : Created. * 1224 *=============================================================================================*/ 1225 fixed INIClass::Get_Fixed(char const * section, char const * entry, fixed defvalue) const 1226 { 1227 char buffer[128]; 1228 fixed retval = defvalue; 1229 1230 if (Get_String(section, entry, "", buffer, sizeof(buffer))) { 1231 retval = fixed(buffer); 1232 } 1233 return(retval); 1234 } 1235 1236 1237 /*********************************************************************************************** 1238 * INIClass::Put_Fixed -- Store a fixed point number to the INI database. * 1239 * * 1240 * Use this routine to output a fixed point number to the database. The entry will be * 1241 * placed in the section and entry specified. If there was any existing entry, it will * 1242 * be replaced. * 1243 * * 1244 * INPUT: section -- Pointer to the section identifier. * 1245 * * 1246 * entry -- Pointer to the entry identifier to use for this value. * 1247 * * 1248 * value -- The value to store in the database. * 1249 * * 1250 * OUTPUT: bool; Was the data stored? * 1251 * * 1252 * WARNINGS: none * 1253 * * 1254 * HISTORY: * 1255 * 07/03/1996 JLB : Created. * 1256 *=============================================================================================*/ 1257 bool INIClass::Put_Fixed(char const * section, char const * entry, fixed value) 1258 { 1259 return(Put_String(section, entry, value.As_ASCII())); 1260 } 1261 1262 1263 /*********************************************************************************************** 1264 * INIClass::Strip_Comments -- Strips comments of the specified text line. * 1265 * * 1266 * This routine will scan the string (text line) supplied and if any comment portions are * 1267 * found, they will be trimmed off. Leading and trailing blanks are also removed. * 1268 * * 1269 * INPUT: buffer -- Pointer to the null terminate string to be processed. * 1270 * * 1271 * OUTPUT: none * 1272 * * 1273 * WARNINGS: none * 1274 * * 1275 * HISTORY: * 1276 * 07/03/1996 JLB : Created. * 1277 *=============================================================================================*/ 1278 void INIClass::Strip_Comments(char * buffer) 1279 { 1280 if (buffer != NULL) { 1281 char * comment = strchr(buffer, ';'); 1282 if (comment) { 1283 *comment = '\0'; 1284 strtrim(buffer); 1285 } 1286 } 1287 }