INI.CPP 71 KB

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