ini.cpp 126 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Command & Conquer *
  23. * *
  24. * $Archive:: /Commando/Code/wwlib/ini.cpp $*
  25. * *
  26. * $Author:: Steve_t $*
  27. * *
  28. * $Modtime:: 11/14/01 1:33a $*
  29. * *
  30. * $Revision:: 22 $*
  31. * *
  32. * Project Name : Command & Conquer *
  33. * *
  34. * $Archive:: /Commando/Code/wwlib/ini.cpp $*
  35. * *
  36. * $Author:: Steve_t $*
  37. * *
  38. * $Modtime:: 11/14/01 1:33a $*
  39. * *
  40. * $Revision:: 22 $*
  41. * *
  42. *---------------------------------------------------------------------------------------------*
  43. * Functions: *
  44. * INIClass::Clear -- Clears out a section (or all sections) of the INI data. *
  45. * INIClass::Get_Filename -- Returns the name of the INI file (if available - "<unknown>" otherwise) *
  46. * INIClass::Entry_Count -- Fetches the number of entries in a specified section. *
  47. * INIClass::Find_Entry -- Find specified entry within section. *
  48. * INIClass::Find_Section -- Find the specified section within the INI data. *
  49. * INIClass::Get_Bool -- Fetch a boolean value for the section and entry specified. *
  50. * INIClass::Get_Entry -- Get the entry identifier name given ordinal number and section name*
  51. * INIClass::Get_Float -- Fetch a floating point number from the database. *
  52. * INIClass::Get_Hex -- Fetches integer [hex format] from the section and entry specified. *
  53. * INIClass::Get_Int -- Fetch an integer entry from the specified section. *
  54. * INIClass::Get_PKey -- Fetch a key from the ini database. *
  55. * INIClass::Get_String -- Fetch the value of a particular entry in a specified section. *
  56. * INIClass::Get_TextBlock -- Fetch a block of normal text. *
  57. * INIClass::Get_UUBlock -- Fetch an encoded block from the section specified. *
  58. * INIClass::INISection::Find_Entry -- Finds a specified entry and returns pointer to it. *
  59. * INIClass::Load -- Load INI data from the file specified. *
  60. * INIClass::Load -- Load the INI data from the data stream (straw). *
  61. * INIClass::Put_Bool -- Store a boolean value into the INI database. *
  62. * INIClass::Put_Float -- Store a floating point number to the database. *
  63. * INIClass::Put_Hex -- Store an integer into the INI database, but use a hex format. *
  64. * INIClass::Put_Int -- Stores a signed integer into the INI data base. *
  65. * INIClass::Put_PKey -- Stores the key to the INI database. *
  66. * INIClass::Put_String -- Output a string to the section and entry specified. *
  67. * INIClass::Put_TextBlock -- Stores a block of text into an INI section. *
  68. * INIClass::Put_UUBlock -- Store a binary encoded data block into the INI database. *
  69. * INIClass::Save -- Save the ini data to the file specified. *
  70. * INIClass::Save -- Saves the INI data to a pipe stream. *
  71. * INIClass::Section_Count -- Counts the number of sections in the INI data. *
  72. * INIClass::Strip_Comments -- Strips comments of the specified text line. *
  73. * INIClass::~INIClass -- Destructor for INI handler. *
  74. * INIClass::Put_Rect -- Store a rectangle into the INI database. *
  75. * INIClass::Get_Rect -- Retrieve a rectangle data from the database. *
  76. * INIClass::Put_Point -- Store a point value to the database. *
  77. * INIClass::Get_Point -- Fetch a point value from the INI database. *
  78. * INIClass::Put_Point -- Stores a 3D point to the database. *
  79. * INIClass::Get_Point -- Fetch a 3D point from the database. *
  80. * INIClass::Get_Point -- Fetch a 2D point from the INI database. *
  81. * INIClass::CRC - returns a (hopefully) unique 32-bit value for a string *
  82. * -- Displays debug information when a duplicate entry is found in an INI file *
  83. * INIClass::Enumerate_Entries -- Count how many entries begin with a certain prefix followed by a range *
  84. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  85. #include "always.h"
  86. #include "b64pipe.h"
  87. #include "b64straw.h"
  88. #include "cstraw.h"
  89. #include "ini.h"
  90. #include "readline.h"
  91. #include "trim.h"
  92. #include "win.h"
  93. #include "xpipe.h"
  94. #include "xstraw.h"
  95. #include <stdio.h>
  96. #include <malloc.h>
  97. #ifdef _UNIX
  98. #include <ctype.h>
  99. #endif
  100. #include "rawfile.h"
  101. #include "ffactory.h"
  102. // recently transferred from ini.h
  103. #include "inisup.h"
  104. #include "trect.h"
  105. #include "wwfile.h"
  106. #include "pk.h"
  107. #include "pipe.h"
  108. #include "wwstring.h"
  109. #include "widestring.h"
  110. #include "nstrdup.h"
  111. #if defined(__WATCOMC__)
  112. // Disable the "temporary object used to initialize a non-constant reference" warning.
  113. #pragma warning 665 9
  114. #endif
  115. // Instance of the static variable.
  116. bool INIClass::KeepBlankEntries = false;
  117. INIEntry::~INIEntry(void)
  118. {
  119. free(Entry);
  120. Entry = NULL;
  121. free(Value);
  122. Value = NULL;
  123. }
  124. INISection::~INISection(void)
  125. {
  126. free(Section);
  127. Section = 0;
  128. EntryList.Delete();
  129. }
  130. bool INIClass::Is_Loaded(void) const
  131. {
  132. return(!SectionList->Is_Empty());
  133. }
  134. void INIClass::Initialize(void)
  135. {
  136. SectionList = new List<INISection *> ();
  137. SectionIndex = new IndexClass<int, INISection *> ();
  138. Filename = nstrdup("<unknown>");
  139. }
  140. void INIClass::Shutdown(void)
  141. {
  142. delete SectionList;
  143. delete SectionIndex;
  144. delete[] Filename;
  145. }
  146. /***********************************************************************************************
  147. * INIClass::INIClass -- Constructor for INI handler. *
  148. * *
  149. * *
  150. * INPUT: FileClass object *
  151. * *
  152. * OUTPUT: none *
  153. * *
  154. * WARNINGS: none *
  155. * *
  156. * HISTORY: *
  157. *=============================================================================================*/
  158. INIClass::INIClass(void)
  159. : Filename(0)
  160. {
  161. Initialize();
  162. }
  163. /***********************************************************************************************
  164. * INIClass::INIClass -- Constructor for INI handler. *
  165. * *
  166. * *
  167. * INPUT: FileClass object *
  168. * *
  169. * OUTPUT: none *
  170. * *
  171. * WARNINGS: none *
  172. * *
  173. * HISTORY: *
  174. *=============================================================================================*/
  175. INIClass::INIClass(FileClass & file)
  176. : Filename(0)
  177. {
  178. Initialize();
  179. Load(file);
  180. }
  181. /***********************************************************************************************
  182. * INIClass::INIClass -- Constructor for INI handler. *
  183. * *
  184. * *
  185. * INPUT: filename string *
  186. * *
  187. * OUTPUT: none *
  188. * *
  189. * WARNINGS: none *
  190. * *
  191. * HISTORY: *
  192. *=============================================================================================*/
  193. INIClass::INIClass(const char *filename)
  194. : Filename(0)
  195. {
  196. Initialize();
  197. FileClass *file=_TheFileFactory->Get_File(filename);
  198. if ( file ) {
  199. Load(*file);
  200. _TheFileFactory->Return_File(file);
  201. }
  202. }
  203. /***********************************************************************************************
  204. * INIClass::~INIClass -- Destructor for INI handler. *
  205. * *
  206. * This is the destructor for the INI class. It handles deleting all of the allocations *
  207. * it might have done. *
  208. * *
  209. * INPUT: none *
  210. * *
  211. * OUTPUT: none *
  212. * *
  213. * WARNINGS: none *
  214. * *
  215. * HISTORY: *
  216. * 07/02/1996 JLB : Created. *
  217. *=============================================================================================*/
  218. INIClass::~INIClass(void)
  219. {
  220. Clear();
  221. Shutdown();
  222. }
  223. /***********************************************************************************************
  224. * INIClass::Clear -- Clears out a section (or all sections) of the INI data. *
  225. * *
  226. * This routine is used to clear out the section specified. If no section is specified, *
  227. * then the entire INI data is cleared out. Optionally, this routine can be used to clear *
  228. * out just an individual entry in the specified section. *
  229. * *
  230. * INPUT: section -- Pointer to the section to clear out [pass NULL to clear all]. *
  231. * *
  232. * entry -- Pointer to optional entry specifier. If this parameter is specified, *
  233. * then only this specific entry (if found) will be cleared. Otherwise, *
  234. * the entire section specified will be cleared. *
  235. * *
  236. * OUTPUT: none *
  237. * *
  238. * WARNINGS: none *
  239. * *
  240. * HISTORY: *
  241. * 07/02/1996 JLB : Created. *
  242. * 08/21/1996 JLB : Optionally clears section too. *
  243. * 11/02/1996 JLB : Updates the index list. *
  244. *=============================================================================================*/
  245. bool INIClass::Clear(char const * section, char const * entry)
  246. {
  247. if (section == NULL) {
  248. SectionList->Delete();
  249. SectionIndex->Clear();
  250. delete[] Filename;
  251. Filename = nstrdup("<unknown>");
  252. } else {
  253. INISection * secptr = Find_Section(section);
  254. if (secptr != NULL) {
  255. if (entry != NULL) {
  256. INIEntry * entptr = secptr->Find_Entry(entry);
  257. if (entptr != NULL) {
  258. /*
  259. ** Remove the entry from the entry index list.
  260. */
  261. secptr->EntryIndex.Remove_Index(entptr->Index_ID());
  262. delete entptr;
  263. }
  264. } else {
  265. /*
  266. ** Remove this section index from the section index list.
  267. */
  268. SectionIndex->Remove_Index(secptr->Index_ID());
  269. delete secptr;
  270. }
  271. }
  272. }
  273. return(true);
  274. }
  275. /***********************************************************************************************
  276. * INIClass::Get_Filename -- Returns the name of the INI file (if available - "<unknown>" *
  277. * otherwise) *
  278. * *
  279. * INPUT: *
  280. * *
  281. * OUTPUT: *
  282. * *
  283. * WARNINGS: *
  284. * *
  285. * HISTORY: *
  286. * 9/7/2001 AJA: Created. *
  287. *=============================================================================================*/
  288. const char * INIClass::Get_Filename (void) const
  289. {
  290. return Filename;
  291. }
  292. /***********************************************************************************************
  293. * INIClass::Load -- Load INI data from the file specified. *
  294. * *
  295. * Use this routine to load the INI class with the data from the specified file. *
  296. * *
  297. * INPUT: file -- Reference to the file that will be used to fill up this INI manager. *
  298. * *
  299. * OUTPUT: bool; Was the file loaded successfully? *
  300. * *
  301. * WARNINGS: This routine allocates memory. *
  302. * *
  303. * HISTORY: *
  304. * 07/02/1996 JLB : Created. *
  305. *=============================================================================================*/
  306. int INIClass::Load(FileClass & file)
  307. {
  308. FileStraw fs(file);
  309. delete[] Filename;
  310. Filename = nstrdup(file.File_Name());
  311. return(Load(fs));
  312. }
  313. /***********************************************************************************************
  314. * INIClass::Load -- Load INI data from the file specified. *
  315. * *
  316. * Use this routine to load the INI class with the data from the specified file. *
  317. * *
  318. * INPUT: filename -- Path for the file to open, factory - thing to make file *
  319. * *
  320. * OUTPUT: bool; Was the file loaded successfully? *
  321. * *
  322. * WARNINGS: This routine allocates memory. *
  323. * *
  324. * HISTORY: *
  325. * 08/01/2000 NAK : Created. *
  326. *=============================================================================================*/
  327. int INIClass::Load(const char *filename)
  328. {
  329. file_auto_ptr file(_TheFileFactory, filename);
  330. int retval=Load(*file);
  331. delete[] Filename;
  332. Filename = nstrdup(filename);
  333. return(retval);
  334. }
  335. /***********************************************************************************************
  336. * INIClass::Load -- Load the INI data from the data stream (straw). *
  337. * *
  338. * This will fetch data from the straw and build an INI database from it. *
  339. * *
  340. * INPUT: straw -- The straw that the data will be provided from. *
  341. * *
  342. * OUTPUT: bool; Was the database loaded ok? *
  343. * *
  344. * WARNINGS: none *
  345. * *
  346. * HISTORY: *
  347. * 07/10/1996 JLB : Created. *
  348. * 09/29/1997 JLB : Handles the merging case. *
  349. * 12/09/1997 EHC : Detects duplicate entry CRCs and fails in that case *
  350. * 03/22/2001 AJA : Treat "foobar=" as a valid entry with value " ". *
  351. * 08/23/2001 AJA : Make the loading of "foobar=" dependant on the KeepBlankEntries flag. *
  352. *=============================================================================================*/
  353. int INIClass::Load(Straw & ffile)
  354. {
  355. bool end_of_file = false;
  356. char buffer[MAX_LINE_LENGTH];
  357. /*
  358. ** Determine if the INI database has preexisting entries. If it does,
  359. ** then the slower merging method of loading is required.
  360. */
  361. bool merge = false;
  362. if (Section_Count() > 0) {
  363. merge = true;
  364. }
  365. CacheStraw file;
  366. file.Get_From(ffile);
  367. /*
  368. ** Prescan until the first section is found.
  369. */
  370. while (!end_of_file) {
  371. Read_Line(file, buffer, sizeof(buffer), end_of_file);
  372. if (end_of_file) return(false);
  373. if (buffer[0] == '[' && strchr(buffer, ']') != NULL) break;
  374. }
  375. if (merge) {
  376. /*
  377. ** Process a section. The buffer is prefilled with the section name line.
  378. */
  379. while (!end_of_file) {
  380. /*
  381. ** Fetch the section name. Preserve it while the section's entries are
  382. ** being parsed.
  383. */
  384. buffer[0] = ' ';
  385. char * ptr = strchr(buffer, ']');
  386. if (ptr != NULL) *ptr = '\0';
  387. strtrim(buffer);
  388. char section[64];
  389. strcpy(section, buffer);
  390. /*
  391. ** Read in the entries of this section.
  392. */
  393. while (!end_of_file) {
  394. /*
  395. ** If this line is the start of another section, then bail out
  396. ** of the entry loop and let the outer section loop take
  397. ** care of it.
  398. */
  399. int len = Read_Line(file, buffer, sizeof(buffer), end_of_file);
  400. if (buffer[0] == '[' && strchr(buffer, ']') != NULL) break;
  401. /*
  402. ** Determine if this line is a comment or blank line. Throw it out if it is.
  403. */
  404. Strip_Comments(buffer);
  405. if (len == 0 || buffer[0] == ';' || buffer[0] == '=') continue;
  406. /*
  407. ** The line isn't an obvious comment. Make sure that there is the "=" character
  408. ** at an appropriate spot.
  409. */
  410. char * divider = strchr(buffer, '=');
  411. if (!divider) continue;
  412. /*
  413. ** Split the line into entry and value sections. Be sure to catch the
  414. ** "=foobar" and "foobar=" cases. "=foobar" lines are ignored, while
  415. ** "foobar=" lines are might be stored as has having " " as their value,
  416. ** depending on the value of KeepBlankEntries.
  417. */
  418. *divider++ = '\0';
  419. strtrim(buffer);
  420. if (!strlen(buffer)) continue;
  421. strtrim(divider);
  422. if (!strlen(divider)) {
  423. if (KeepBlankEntries)
  424. divider = " ";
  425. else
  426. continue;
  427. }
  428. if (Put_String(section, buffer, divider) == false) {
  429. return(false);
  430. }
  431. }
  432. }
  433. } else {
  434. /*
  435. ** Process a section. The buffer is prefilled with the section name line.
  436. */
  437. while (!end_of_file) {
  438. buffer[0] = ' ';
  439. char * ptr = strchr(buffer, ']');
  440. if (ptr != NULL) *ptr = '\0';
  441. strtrim(buffer);
  442. INISection * secptr = new INISection(strdup(buffer));
  443. if (secptr == NULL) {
  444. Clear();
  445. return(false);
  446. }
  447. /*
  448. ** Read in the entries of this section.
  449. */
  450. while (!end_of_file) {
  451. /*
  452. ** If this line is the start of another section, then bail out
  453. ** of the entry loop and let the outer section loop take
  454. ** care of it.
  455. */
  456. int len = Read_Line(file, buffer, sizeof(buffer), end_of_file);
  457. if (buffer[0] == '[' && strchr(buffer, ']') != NULL) break;
  458. /*
  459. ** Determine if this line is a comment or blank line. Throw it out if it is.
  460. */
  461. Strip_Comments(buffer);
  462. if (len == 0 || buffer[0] == ';' || buffer[0] == '=') continue;
  463. /*
  464. ** The line isn't an obvious comment. Make sure that there is the "=" character
  465. ** at an appropriate spot.
  466. */
  467. char * divider = strchr(buffer, '=');
  468. if (!divider) continue;
  469. /*
  470. ** Split the line into entry and value sections. Be sure to catch the
  471. ** "=foobar" and "foobar=" cases. "=foobar" lines are ignored, while
  472. ** "foobar=" lines are might be stored as has having " " as their value,
  473. ** depending on the value of KeepBlankEntries.
  474. */
  475. *divider++ = '\0';
  476. strtrim(buffer);
  477. if (!strlen(buffer)) continue;
  478. strtrim(divider);
  479. if (!strlen(divider)) {
  480. if (KeepBlankEntries)
  481. divider = " ";
  482. else
  483. continue;
  484. }
  485. INIEntry * entryptr = new INIEntry(strdup(buffer), strdup(divider));
  486. if (entryptr == NULL) {
  487. delete secptr;
  488. Clear();
  489. return(false);
  490. }
  491. // 12/09/97 EHC - check to see if an entry with this ID already exists
  492. if (secptr->EntryIndex.Is_Present(entryptr->Index_ID())) {
  493. DuplicateCRCError("INIClass::Load", secptr->Section, buffer);
  494. delete entryptr;
  495. continue;
  496. }
  497. secptr->EntryIndex.Add_Index(entryptr->Index_ID(), entryptr);
  498. secptr->EntryList.Add_Tail(entryptr);
  499. }
  500. /*
  501. ** All the entries for this section have been parsed. If this section is blank, then
  502. ** don't bother storing it.
  503. */
  504. if (secptr->EntryList.Is_Empty()) {
  505. delete secptr;
  506. } else {
  507. SectionIndex->Add_Index(secptr->Index_ID(), secptr);
  508. SectionList->Add_Tail(secptr);
  509. }
  510. }
  511. }
  512. return(true);
  513. }
  514. /***********************************************************************************************
  515. * INIClass::Save -- Save the ini data to the file specified. *
  516. * *
  517. * Use this routine to save the ini data to the file specified. All existing data in the *
  518. * file, if it was present, is replaced. *
  519. * *
  520. * INPUT: file -- Reference to the file to write the INI data to. *
  521. * *
  522. * OUTPUT: bool; Was the data written to the file? *
  523. * *
  524. * WARNINGS: none *
  525. * *
  526. * HISTORY: *
  527. * 07/02/1996 JLB : Created. *
  528. *=============================================================================================*/
  529. int INIClass::Save(FileClass & file) const
  530. {
  531. FilePipe fp(file);
  532. delete[] Filename;
  533. Filename = nstrdup(file.File_Name());
  534. return(Save(fp));
  535. }
  536. /***********************************************************************************************
  537. * INIClass::Save -- Save the ini data to the file specified. *
  538. * *
  539. * Use this routine to save the ini data to the file specified. All existing data in the *
  540. * file, if it was present, is replaced. *
  541. * *
  542. * INPUT: filename -- Filename to save to. *
  543. * *
  544. * OUTPUT: bool; Was the data written to the file? *
  545. * *
  546. * WARNINGS: none *
  547. * *
  548. * HISTORY: *
  549. * 01/22/2001 NAK : Created. *
  550. *=============================================================================================*/
  551. int INIClass::Save(const char *filename) const
  552. {
  553. FileClass *file=_TheWritingFileFactory->Get_File(filename);
  554. int retval=0;
  555. if ( file ) {
  556. retval=Save(*file);
  557. _TheWritingFileFactory->Return_File(file);
  558. }
  559. file=NULL;
  560. delete[] Filename;
  561. Filename = nstrdup(filename);
  562. return(retval);
  563. }
  564. /***********************************************************************************************
  565. * INIClass::Save -- Saves the INI data to a pipe stream. *
  566. * *
  567. * This routine will output the data of the INI file to a pipe stream. *
  568. * *
  569. * INPUT: pipe -- Reference to the pipe stream to pump the INI image to. *
  570. * *
  571. * OUTPUT: Returns with the number of bytes output to the pipe. *
  572. * *
  573. * WARNINGS: none *
  574. * *
  575. * HISTORY: *
  576. * 07/02/1996 JLB : Created. *
  577. *=============================================================================================*/
  578. int INIClass::Save(Pipe & pipe) const
  579. {
  580. int total = 0;
  581. #ifdef _UNIX
  582. const char *EOL="\n";
  583. #else
  584. const char *EOL="\r\n";
  585. #endif
  586. INISection * secptr = SectionList->First();
  587. while (secptr && secptr->Is_Valid()) {
  588. /*
  589. ** Output the section identifier.
  590. */
  591. total += pipe.Put("[", 1);
  592. total += pipe.Put(secptr->Section, strlen(secptr->Section));
  593. total += pipe.Put("]", 1);
  594. total += pipe.Put(EOL, strlen(EOL));
  595. /*
  596. ** Output all the entries and values in this section.
  597. */
  598. INIEntry * entryptr = secptr->EntryList.First();
  599. while (entryptr && entryptr->Is_Valid()) {
  600. total += pipe.Put(entryptr->Entry, strlen(entryptr->Entry));
  601. total += pipe.Put("=", 1);
  602. total += pipe.Put(entryptr->Value, strlen(entryptr->Value));
  603. total += pipe.Put(EOL, strlen(EOL));
  604. entryptr = entryptr->Next();
  605. }
  606. /*
  607. ** After the last entry in this section, output an extra
  608. ** blank line for readability purposes.
  609. */
  610. total += pipe.Put(EOL, strlen(EOL));
  611. secptr = secptr->Next();
  612. }
  613. total += pipe.End();
  614. return(total);
  615. }
  616. /***********************************************************************************************
  617. * INIClass::Find_Section -- Find the specified section within the INI data. *
  618. * *
  619. * This routine will scan through the INI data looking for the section specified. If the *
  620. * section could be found, then a pointer to the section control data is returned. *
  621. * *
  622. * INPUT: section -- The name of the section to search for. Don't enclose the name in *
  623. * brackets. Case is NOT sensitive in the search. *
  624. * *
  625. * OUTPUT: Returns with a pointer to the INI section control structure if the section was *
  626. * found. Otherwise, NULL is returned. *
  627. * *
  628. * WARNINGS: none *
  629. * *
  630. * HISTORY: *
  631. * 07/02/1996 JLB : Created. *
  632. * 11/02/1996 JLB : Uses index manager. *
  633. * 12/08/1996 EHC : Uses member CRC function *
  634. *=============================================================================================*/
  635. INISection * INIClass::Find_Section(char const * section) const
  636. {
  637. if (section != NULL) {
  638. // long crc = CRCEngine()(section, strlen(section));
  639. long crc = CRC(section);
  640. if (SectionIndex->Is_Present(crc)) {
  641. return((*SectionIndex)[crc]);
  642. }
  643. }
  644. return(NULL);
  645. }
  646. /***********************************************************************************************
  647. * INIClass::Section_Count -- Counts the number of sections in the INI data. *
  648. * *
  649. * This routine will scan through all the sections in the INI data and return a count *
  650. * of the number it found. *
  651. * *
  652. * INPUT: none *
  653. * *
  654. * OUTPUT: Returns with the number of sections recorded in the INI data. *
  655. * *
  656. * WARNINGS: none *
  657. * *
  658. * HISTORY: *
  659. * 07/02/1996 JLB : Created. *
  660. * 11/02/1996 JLB : Uses index manager. *
  661. *=============================================================================================*/
  662. int INIClass::Section_Count(void) const
  663. {
  664. return(SectionIndex->Count());
  665. }
  666. /***********************************************************************************************
  667. * INIClass::Entry_Count -- Fetches the number of entries in a specified section. *
  668. * *
  669. * This routine will examine the section specified and return with the number of entries *
  670. * associated with it. *
  671. * *
  672. * INPUT: section -- Pointer to the section that will be examined. *
  673. * *
  674. * OUTPUT: Returns with the number entries in the specified section. *
  675. * *
  676. * WARNINGS: none *
  677. * *
  678. * HISTORY: *
  679. * 07/02/1996 JLB : Created. *
  680. * 11/02/1996 JLB : Uses index manager. *
  681. *=============================================================================================*/
  682. int INIClass::Entry_Count(char const * section) const
  683. {
  684. INISection * secptr = Find_Section(section);
  685. if (secptr != NULL) {
  686. return(secptr->EntryIndex.Count());
  687. }
  688. return(0);
  689. }
  690. /***********************************************************************************************
  691. * INIClass::Find_Entry -- Find specified entry within section. *
  692. * *
  693. * This support routine will find the specified entry in the specified section. If found, *
  694. * a pointer to the entry control structure will be returned. *
  695. * *
  696. * INPUT: section -- Pointer to the section name to search under. *
  697. * *
  698. * entry -- Pointer to the entry name to search for. *
  699. * *
  700. * OUTPUT: If the entry was found, then a pointer to the entry control structure will be *
  701. * returned. Otherwise, NULL will be returned. *
  702. * *
  703. * WARNINGS: none *
  704. * *
  705. * HISTORY: *
  706. * 07/02/1996 JLB : Created. *
  707. *=============================================================================================*/
  708. INIEntry * INIClass::Find_Entry(char const * section, char const * entry) const
  709. {
  710. INISection * secptr = Find_Section(section);
  711. if (secptr != NULL) {
  712. return(secptr->Find_Entry(entry));
  713. }
  714. return(NULL);
  715. }
  716. /***********************************************************************************************
  717. * INIClass::Get_Entry -- Get the entry identifier name given ordinal number and section name. *
  718. * *
  719. * This will return the identifier name for the entry under the section specified. The *
  720. * ordinal number specified is used to determine which entry to retrieve. The entry *
  721. * identifier is the text that appears to the left of the "=" character. *
  722. * *
  723. * INPUT: section -- The section to use. *
  724. * *
  725. * index -- The ordinal number to use when fetching an entry name. *
  726. * *
  727. * OUTPUT: Returns with a pointer to the entry name. *
  728. * *
  729. * WARNINGS: none *
  730. * *
  731. * HISTORY: *
  732. * 07/02/1996 JLB : Created. *
  733. *=============================================================================================*/
  734. char const * INIClass::Get_Entry(char const * section, int index) const
  735. {
  736. INISection * secptr = Find_Section(section);
  737. if (secptr != NULL && index < secptr->EntryIndex.Count()) {
  738. INIEntry * entryptr = secptr->EntryList.First();
  739. while (entryptr != NULL && entryptr->Is_Valid()) {
  740. if (index == 0) return(entryptr->Entry);
  741. index--;
  742. entryptr = entryptr->Next();
  743. }
  744. }
  745. return(NULL);
  746. }
  747. /***********************************************************************************************
  748. * Enumerate_Entries -- Count how many entries begin with a certain prefix followed by a range *
  749. * of numbers. *
  750. * *
  751. * *
  752. * *
  753. * *
  754. * INPUT: *
  755. * *
  756. * OUTPUT: *
  757. * *
  758. * WARNINGS: *
  759. * *
  760. * HISTORY: *
  761. * 9/29/99 EHC : Created. *
  762. *=============================================================================================*/
  763. unsigned INIClass::Enumerate_Entries(const char *Section, const char * Entry_Prefix, unsigned StartNumber, unsigned EndNumber)
  764. {
  765. unsigned count = StartNumber;
  766. bool present = false;
  767. char entry[256];
  768. do
  769. {
  770. sprintf(entry, "%s%d", Entry_Prefix, count);
  771. present = Is_Present(Section, entry);
  772. if(present)
  773. count++;
  774. } while(present && (count < EndNumber));
  775. return (count - StartNumber);
  776. }
  777. /***********************************************************************************************
  778. * INIClass::Put_UUBlock -- Store a binary encoded data block into the INI database. *
  779. * *
  780. * Use this routine to store an arbitrary length binary block of data into the INI database.*
  781. * This routine will covert the data into displayable form and then break it into lines *
  782. * that are stored in sequence to the section. A section used to store data in this *
  783. * fashion can not be used for any other entries. *
  784. * *
  785. * INPUT: section -- The section identifier to place the data into. *
  786. * *
  787. * block -- Pointer to the block of binary data to store. *
  788. * *
  789. * len -- The length of the binary data. *
  790. * *
  791. * OUTPUT: bool; Was the data stored to the database? *
  792. * *
  793. * WARNINGS: none *
  794. * *
  795. * HISTORY: *
  796. * 07/03/1996 JLB : Created. *
  797. *=============================================================================================*/
  798. bool INIClass::Put_UUBlock(char const * section, void const * block, int len)
  799. {
  800. if (section == NULL || block == NULL || len < 1) return(false);
  801. Clear(section);
  802. BufferStraw straw(block, len);
  803. Base64Straw bstraw(Base64Straw::ENCODE);
  804. bstraw.Get_From(straw);
  805. int counter = 1;
  806. for (;;) {
  807. char buffer[71];
  808. char sbuffer[32];
  809. int length = bstraw.Get(buffer, sizeof(buffer)-1);
  810. buffer[length] = '\0';
  811. if (length == 0) break;
  812. sprintf(sbuffer, "%d", counter);
  813. Put_String(section, sbuffer, buffer);
  814. counter++;
  815. }
  816. return(true);
  817. }
  818. /***********************************************************************************************
  819. * INIClass::Get_UUBlock -- Fetch an encoded block from the section specified. *
  820. * *
  821. * This routine will take all the entries in the specified section and decompose them into *
  822. * a binary block of data that will be stored into the buffer specified. By using this *
  823. * routine [and the Put_UUBLock counterpart], arbitrary blocks of binary data may be *
  824. * stored in the INI file. A section processed by this routine can contain no other *
  825. * entries than those put there by a previous call to Put_UUBlock. *
  826. * *
  827. * INPUT: section -- The section name to process. *
  828. * *
  829. * block -- Pointer to the buffer that will hold the retrieved data. *
  830. * *
  831. * len -- The length of the buffer. The retrieved data will not fill past this *
  832. * limit. *
  833. * *
  834. * OUTPUT: Returns with the number of bytes decoded into the buffer specified. *
  835. * *
  836. * WARNINGS: If the number of bytes retrieved exactly matches the length of the buffer *
  837. * specified, then you might have a condition of buffer "overflow". *
  838. * *
  839. * HISTORY: *
  840. * 07/02/1996 JLB : Created. *
  841. *=============================================================================================*/
  842. int INIClass::Get_UUBlock(char const * section, void * block, int len) const
  843. {
  844. if (section == NULL) return(0);
  845. Base64Pipe b64pipe(Base64Pipe::DECODE);
  846. BufferPipe bpipe(block, len);
  847. b64pipe.Put_To(&bpipe);
  848. int total = 0;
  849. int counter = Entry_Count(section);
  850. for (int index = 0; index < counter; index++) {
  851. char buffer[128];
  852. int length = Get_String(section, Get_Entry(section, index), "=", buffer, sizeof(buffer));
  853. int outcount = b64pipe.Put(buffer, length);
  854. total += outcount;
  855. }
  856. total += b64pipe.End();
  857. return(total);
  858. }
  859. /***********************************************************************************************
  860. * INIClass::Get_Wide_String -- Get a wide string from an .INI *
  861. * *
  862. * *
  863. * *
  864. * INPUT: Reference to new string to return *
  865. * Section to find string *
  866. * Entry name of string *
  867. * Default value to use when string is not present *
  868. * *
  869. * OUTPUT: Reference to input string *
  870. * *
  871. * WARNINGS: None *
  872. * *
  873. * HISTORY: *
  874. * 11/6/2001 4:27PM ST : Created *
  875. *=============================================================================================*/
  876. const WideStringClass& INIClass::Get_Wide_String(WideStringClass& new_string, char const * section, char const * entry, unsigned short const * defvalue) const
  877. {
  878. unsigned short out[1024];
  879. char buffer[1024];
  880. Base64Pipe b64pipe(Base64Pipe::DECODE);
  881. BufferPipe bpipe(out, sizeof(out));
  882. b64pipe.Put_To(&bpipe);
  883. int length = Get_String(section, entry, "", buffer, sizeof(buffer));
  884. if (length == 0) {
  885. new_string = defvalue;
  886. } else {
  887. int outcount = b64pipe.Put(buffer, length);
  888. outcount += b64pipe.End();
  889. new_string = out;
  890. }
  891. return(new_string);
  892. }
  893. /***********************************************************************************************
  894. * INIClass::Put_Wide_String -- Put a wide string into an INI database. *
  895. * *
  896. * *
  897. * *
  898. * INPUT: Section name to store entry under *
  899. * Entry name *
  900. * Ptr to wide string data *
  901. * *
  902. * OUTPUT: True if put OK *
  903. * *
  904. * WARNINGS: None *
  905. * *
  906. * HISTORY: *
  907. * 11/6/2001 4:29PM ST : Created *
  908. *=============================================================================================*/
  909. bool INIClass::Put_Wide_String(char const * section, char const * entry, const unsigned short * string)
  910. {
  911. if (section == NULL || entry == NULL || string == NULL) {
  912. return(false);
  913. }
  914. WideStringClass temp_string(string, true);
  915. int len = temp_string.Get_Length();
  916. if (len == 0) {
  917. Put_String(section, entry, "");
  918. } else {
  919. char *buffer = (char*) _alloca((len * 8) + 32);
  920. BufferStraw straw(string, (len*2) + 2); // Convert from shorts to bytes, plus 2 for terminator.
  921. Base64Straw bstraw(Base64Straw::ENCODE);
  922. bstraw.Get_From(straw);
  923. int new_length = 0;
  924. int added = 0;
  925. do {
  926. added = bstraw.Get(buffer + new_length, 16);
  927. new_length += added;
  928. } while (added);
  929. buffer[new_length] = 0;
  930. WWASSERT(new_length != 0);
  931. Put_String(section, entry, buffer);
  932. }
  933. return(true);
  934. }
  935. bool INIClass::Put_UUBlock(char const * section, char const *entry, void const * block, int len)
  936. {
  937. if (section == NULL || block == NULL || len < 1) return(false);
  938. BufferStraw straw(block, len);
  939. Base64Straw bstraw(Base64Straw::ENCODE);
  940. bstraw.Get_From(straw);
  941. char *buffer = (char*) _alloca(len * 3);
  942. int length = bstraw.Get(buffer, (len * 3) - 1);
  943. buffer[length] = '\0';
  944. Put_String(section, entry, buffer);
  945. return(true);
  946. }
  947. int INIClass::Get_UUBlock(char const * section, char const *entry, void * block, int len) const
  948. {
  949. if (section == NULL) return(0);
  950. if (entry == NULL) return(0);
  951. Base64Pipe b64pipe(Base64Pipe::DECODE);
  952. BufferPipe bpipe(block, len);
  953. b64pipe.Put_To(&bpipe);
  954. int total = 0;
  955. char *buffer = (char*) _alloca(len * 3);
  956. int length = Get_String(section, entry, "=", buffer, len*3);
  957. int outcount = b64pipe.Put(buffer, length);
  958. total += outcount;
  959. total += b64pipe.End();
  960. return(total);
  961. }
  962. /***********************************************************************************************
  963. * INIClass::Put_TextBlock -- Stores a block of text into an INI section. *
  964. * *
  965. * This routine will take an arbitrarily long block of text and store it into the INI *
  966. * database. The text is broken up into lines and each line is then stored as a numbered *
  967. * entry in the specified section. A section used to store text in this way can not be used *
  968. * to hold any other entries. The text is presumed to contain space characters scattered *
  969. * throughout it and that one space between words and sentences is natural. *
  970. * *
  971. * INPUT: section -- The section to place the text block into. *
  972. * *
  973. * text -- Pointer to a null terminated text string that holds the block of *
  974. * text. The length can be arbitrary. *
  975. * *
  976. * OUTPUT: bool; Was the text block placed into the database? *
  977. * *
  978. * WARNINGS: none *
  979. * *
  980. * HISTORY: *
  981. * 07/03/1996 JLB : Created. *
  982. *=============================================================================================*/
  983. bool INIClass::Put_TextBlock(char const * section, char const * text)
  984. {
  985. if (section == NULL) return(false);
  986. Clear(section);
  987. int index = 1;
  988. while (text != NULL && *text != 0) {
  989. char buffer[128];
  990. strncpy(buffer, text, 75);
  991. buffer[75] = '\0';
  992. char b[32];
  993. sprintf(b, "%d", index);
  994. /*
  995. ** Scan backward looking for a good break position.
  996. */
  997. int count = strlen(buffer);
  998. if (count > 0) {
  999. if (count >= 75) {
  1000. while (count) {
  1001. char c = buffer[count];
  1002. if (isspace(c)) break;
  1003. count--;
  1004. }
  1005. if (count == 0) {
  1006. break;
  1007. } else {
  1008. buffer[count] = '\0';
  1009. }
  1010. }
  1011. strtrim(buffer);
  1012. Put_String(section, b, buffer);
  1013. index++;
  1014. text = ((char *)text) + count;
  1015. } else {
  1016. break;
  1017. }
  1018. }
  1019. return(true);
  1020. }
  1021. /***********************************************************************************************
  1022. * INIClass::Get_TextBlock -- Fetch a block of normal text. *
  1023. * *
  1024. * This will take all entries in the specified section and format them into a block of *
  1025. * normalized text. That is, text with single spaces between each concatenated line. All *
  1026. * entries in the specified section are processed by this routine. Use Put_TextBlock to *
  1027. * build the entries in the section. *
  1028. * *
  1029. * INPUT: section -- The section name to process. *
  1030. * *
  1031. * buffer -- Pointer to the buffer that will hold the complete text. *
  1032. * *
  1033. * len -- The length of the buffer specified. The text will, at most, fill this *
  1034. * buffer with the last character being forced to null. *
  1035. * *
  1036. * OUTPUT: Returns with the number of characters placed into the buffer. The trailing null *
  1037. * is not counted. *
  1038. * *
  1039. * WARNINGS: none *
  1040. * *
  1041. * HISTORY: *
  1042. * 07/02/1996 JLB : Created. *
  1043. *=============================================================================================*/
  1044. int INIClass::Get_TextBlock(char const * section, char * buffer, int len) const
  1045. {
  1046. if (len <= 0) return(0);
  1047. buffer[0] = '\0';
  1048. if (len <= 1) return(0);
  1049. int elen = Entry_Count(section);
  1050. int total = 0;
  1051. for (int index = 0; index < elen; index++) {
  1052. /*
  1053. ** Add spacers between lines of fetched text.
  1054. */
  1055. if (index > 0) {
  1056. *buffer++ = ' ';
  1057. len--;
  1058. total++;
  1059. }
  1060. Get_String(section, Get_Entry(section, index), "", buffer, len);
  1061. int partial = strlen(buffer);
  1062. total += partial;
  1063. buffer += partial;
  1064. len -= partial;
  1065. if (len <= 1) break;
  1066. }
  1067. return(total);
  1068. }
  1069. /***********************************************************************************************
  1070. * INIClass::Put_Int -- Stores a signed integer into the INI data base. *
  1071. * *
  1072. * Use this routine to store an integer value into the section and entry specified. *
  1073. * *
  1074. * INPUT: section -- The identifier for the section that the entry will be placed in. *
  1075. * *
  1076. * entry -- The entry identifier used for the integer number. *
  1077. * *
  1078. * number -- The integer number to store in the database. *
  1079. * *
  1080. * format -- The format to store the integer. The format is generally only a *
  1081. * cosmetic affect. The Get_Int operation will interpret the value the *
  1082. * same regardless of what format was used to store the integer. *
  1083. * *
  1084. * 0 : plain decimal digit *
  1085. * 1 : hexadecimal digit (trailing "h") *
  1086. * 2 : hexadecimal digit (leading "$") *
  1087. * *
  1088. * OUTPUT: bool; Was the number stored? *
  1089. * *
  1090. * WARNINGS: none *
  1091. * *
  1092. * HISTORY: *
  1093. * 07/03/1996 JLB : Created. *
  1094. * 07/10/1996 JLB : Handles multiple integer formats. *
  1095. *=============================================================================================*/
  1096. bool INIClass::Put_Int(char const * section, char const * entry, int number, int format)
  1097. {
  1098. char buffer[MAX_LINE_LENGTH];
  1099. switch (format) {
  1100. default:
  1101. case 0:
  1102. sprintf(buffer, "%d", number);
  1103. break;
  1104. case 1:
  1105. sprintf(buffer, "%Xh", number);
  1106. break;
  1107. case 2:
  1108. sprintf(buffer, "$%X", number);
  1109. break;
  1110. }
  1111. return(Put_String(section, entry, buffer));
  1112. }
  1113. /***********************************************************************************************
  1114. * INIClass::Get_Int -- Fetch an integer entry from the specified section. *
  1115. * *
  1116. * This routine will fetch an integer value from the entry and section specified. If no *
  1117. * entry could be found, then the default value will be returned instead. *
  1118. * *
  1119. * INPUT: section -- The section name to search under. *
  1120. * *
  1121. * entry -- The entry name to search for. *
  1122. * *
  1123. * defvalue -- The default value to use if the specified entry could not be found. *
  1124. * *
  1125. * OUTPUT: Returns with the integer value specified in the INI database or else returns the *
  1126. * default value. *
  1127. * *
  1128. * WARNINGS: none *
  1129. * *
  1130. * HISTORY: *
  1131. * 07/02/1996 JLB : Created. *
  1132. * 07/10/1996 JLB : Handles multiple integer formats. *
  1133. *=============================================================================================*/
  1134. int INIClass::Get_Int(char const * section, char const * entry, int defvalue) const
  1135. {
  1136. /*
  1137. ** Verify that the parameters are nominally correct.
  1138. */
  1139. if (section == NULL || entry == NULL) return(defvalue);
  1140. INIEntry * entryptr = Find_Entry(section, entry);
  1141. if (entryptr && entryptr->Value != NULL) {
  1142. if (*entryptr->Value == '$') {
  1143. sscanf(entryptr->Value, "$%x", &defvalue);
  1144. } else {
  1145. if (tolower(entryptr->Value[strlen(entryptr->Value)-1]) == 'h') {
  1146. sscanf(entryptr->Value, "%xh", &defvalue);
  1147. } else {
  1148. defvalue = atoi(entryptr->Value);
  1149. }
  1150. }
  1151. }
  1152. return(defvalue);
  1153. }
  1154. /***********************************************************************************************
  1155. * INIClass::Put_Rect -- Store a rectangle into the INI database. *
  1156. * *
  1157. * This routine will store the four values that constitute the specified rectangle into *
  1158. * the database under the section and entry specified. *
  1159. * *
  1160. * INPUT: section -- Name of the section to place the entry under. *
  1161. * *
  1162. * entry -- Name of the entry that the rectangle data will be stored to. *
  1163. * *
  1164. * value -- The rectangle value to store. *
  1165. * *
  1166. * OUTPUT: bool; Was the rectangle data written to the database? *
  1167. * *
  1168. * WARNINGS: none *
  1169. * *
  1170. * HISTORY: *
  1171. * 09/19/1997 JLB : Created. *
  1172. *=============================================================================================*/
  1173. bool INIClass::Put_Rect(char const * section, char const * entry, Rect const & value)
  1174. {
  1175. char buffer[64];
  1176. sprintf(buffer, "%d,%d,%d,%d", value.X, value.Y, value.Width, value.Height);
  1177. return(Put_String(section, entry, buffer));
  1178. }
  1179. /***********************************************************************************************
  1180. * INIClass::Get_Rect -- Retrieve a rectangle data from the database. *
  1181. * *
  1182. * This routine will retrieve the rectangle data from the database at the section and entry *
  1183. * specified. *
  1184. * *
  1185. * INPUT: section -- The name of the section that the entry will be scanned for. *
  1186. * *
  1187. * entry -- The entry that the rectangle data will be lifted from. *
  1188. * *
  1189. * defvalue -- The rectangle value to return if the specified section and entry could *
  1190. * not be found. *
  1191. * *
  1192. * OUTPUT: Returns with the rectangle data from the database or the default value if not *
  1193. * found. *
  1194. * *
  1195. * WARNINGS: none *
  1196. * *
  1197. * HISTORY: *
  1198. * 09/19/1997 JLB : Created. *
  1199. *=============================================================================================*/
  1200. Rect const INIClass::Get_Rect(char const * section, char const * entry, Rect const & defvalue) const
  1201. {
  1202. char buffer[64];
  1203. if (Get_String(section, entry, "0,0,0,0", buffer, sizeof(buffer))) {
  1204. Rect retval = defvalue;
  1205. sscanf(buffer, "%d,%d,%d,%d", &retval.X, &retval.Y, &retval.Width, &retval.Height);
  1206. return(retval);
  1207. }
  1208. return(defvalue);
  1209. }
  1210. /***********************************************************************************************
  1211. * INIClass::Put_Hex -- Store an integer into the INI database, but use a hex format. *
  1212. * *
  1213. * This routine is similar to the Put_Int routine, but the number is stored as a hexadecimal*
  1214. * number. *
  1215. * *
  1216. * INPUT: section -- The identifier for the section that the entry will be placed in. *
  1217. * *
  1218. * entry -- The entry identifier to tag to the integer number specified. *
  1219. * *
  1220. * number -- The number to assign the the specified entry and placed in the *
  1221. * specified section. *
  1222. * *
  1223. * OUTPUT: bool; Was the number placed into the INI database? *
  1224. * *
  1225. * WARNINGS: none *
  1226. * *
  1227. * HISTORY: *
  1228. * 07/03/1996 JLB : Created. *
  1229. *=============================================================================================*/
  1230. bool INIClass::Put_Hex(char const * section, char const * entry, int number)
  1231. {
  1232. char buffer[MAX_LINE_LENGTH];
  1233. sprintf(buffer, "%X", number);
  1234. return(Put_String(section, entry, buffer));
  1235. }
  1236. /***********************************************************************************************
  1237. * INIClass::Get_Hex -- Fetches integer [hex format] from the section and entry specified. *
  1238. * *
  1239. * This routine will search under the section specified, looking for a matching entry. The *
  1240. * value is interpreted as a hexadecimal number and then returned. If no entry could be *
  1241. * found, then the default value is returned instead. *
  1242. * *
  1243. * INPUT: section -- The section identifier to search under. *
  1244. * *
  1245. * entry -- The entry identifier to search for. *
  1246. * *
  1247. * defvalue -- The default value to use if the entry could not be located. *
  1248. * *
  1249. * OUTPUT: Returns with the integer value from the specified section and entry. If no entry *
  1250. * could be found, then the default value will be returned instead. *
  1251. * *
  1252. * WARNINGS: none *
  1253. * *
  1254. * HISTORY: *
  1255. * 07/02/1996 JLB : Created. *
  1256. *=============================================================================================*/
  1257. int INIClass::Get_Hex(char const * section, char const * entry, int defvalue) const
  1258. {
  1259. /*
  1260. ** Verify that the parameters are nominally correct.
  1261. */
  1262. if (section == NULL || entry == NULL) return(defvalue);
  1263. INIEntry * entryptr = Find_Entry(section, entry);
  1264. if (entryptr && entryptr->Value != NULL) {
  1265. sscanf(entryptr->Value, "%x", &defvalue);
  1266. }
  1267. return(defvalue);
  1268. }
  1269. /***********************************************************************************************
  1270. * INIClass::Get_Float -- Fetch a floating point number from the database. *
  1271. * *
  1272. * This routine will retrieve a floating point number from the database. *
  1273. * *
  1274. * INPUT: section -- The section name to find the entry under. *
  1275. * *
  1276. * entry -- The entry name to fetch the float value from. *
  1277. * *
  1278. * defvalue -- Return value to use if the section and entry could not be found. *
  1279. * *
  1280. * OUTPUT: Returns with the float value from the section and entry specified. If not found, *
  1281. * then the default value is returned. *
  1282. * *
  1283. * WARNINGS: none *
  1284. * *
  1285. * HISTORY: *
  1286. * 05/31/1997 JLB : Created. *
  1287. *=============================================================================================*/
  1288. float INIClass::Get_Float(char const * section, char const * entry, float defvalue) const
  1289. {
  1290. /*
  1291. ** Verify that the parameters are nominally correct.
  1292. */
  1293. if (section == NULL || entry == NULL) return(defvalue);
  1294. INIEntry * entryptr = Find_Entry(section, entry);
  1295. if (entryptr != NULL && entryptr->Value != NULL) {
  1296. float val = defvalue;
  1297. sscanf(entryptr->Value, "%f", &val);
  1298. defvalue = val;
  1299. if (strchr(entryptr->Value, '%') != NULL) {
  1300. defvalue /= 100.0f;
  1301. }
  1302. }
  1303. return(defvalue);
  1304. }
  1305. /***********************************************************************************************
  1306. * INIClass::Put_Float -- Store a floating point number to the database. *
  1307. * *
  1308. * This routine will store a flaoting point number to the section and entry of the *
  1309. * database. *
  1310. * *
  1311. * INPUT: section -- The section to store the entry under. *
  1312. * *
  1313. * entry -- The entry to store the floating point number to. *
  1314. * *
  1315. * number -- The floating point number to store. *
  1316. * *
  1317. * OUTPUT: bool; Was the floating point number stored without error? *
  1318. * *
  1319. * WARNINGS: none *
  1320. * *
  1321. * HISTORY: *
  1322. * 05/31/1997 JLB : Created. *
  1323. *=============================================================================================*/
  1324. bool INIClass::Put_Float(char const * section, char const * entry, float number)
  1325. {
  1326. char buffer[MAX_LINE_LENGTH];
  1327. sprintf(buffer, "%f", number);
  1328. return(Put_String(section, entry, buffer));
  1329. }
  1330. /***********************************************************************************************
  1331. * INIClass::Get_Double -- Fetch a double-precision floating point number from the database. *
  1332. * *
  1333. * This routine will retrieve a floating point number from the database. *
  1334. * *
  1335. * INPUT: section -- The section name to find the entry under. *
  1336. * *
  1337. * entry -- The entry name to fetch the float value from. *
  1338. * *
  1339. * defvalue -- Return value to use if the section and entry could not be found. *
  1340. * *
  1341. * OUTPUT: Returns with the float value from the section and entry specified. If not found, *
  1342. * then the default value is returned. *
  1343. * *
  1344. * WARNINGS: none *
  1345. * *
  1346. * HISTORY: *
  1347. * 8/27/2001 AJA : Created. *
  1348. *=============================================================================================*/
  1349. double INIClass::Get_Double(char const * section, char const * entry, double defvalue) const
  1350. {
  1351. /*
  1352. ** Verify that the parameters are nominally correct.
  1353. */
  1354. if (section == NULL || entry == NULL) return(defvalue);
  1355. INIEntry * entryptr = Find_Entry(section, entry);
  1356. if (entryptr != NULL && entryptr->Value != NULL) {
  1357. float val = defvalue;
  1358. sscanf(entryptr->Value, "%lf", &val);
  1359. defvalue = val;
  1360. if (strchr(entryptr->Value, '%') != NULL) {
  1361. defvalue /= 100.0f;
  1362. }
  1363. }
  1364. return(defvalue);
  1365. }
  1366. /***********************************************************************************************
  1367. * INIClass::Put_Double -- Store a double-precision floating point number to the database. *
  1368. * *
  1369. * This routine will store a flaoting point number to the section and entry of the *
  1370. * database. *
  1371. * *
  1372. * INPUT: section -- The section to store the entry under. *
  1373. * *
  1374. * entry -- The entry to store the floating point number to. *
  1375. * *
  1376. * number -- The floating point number to store. *
  1377. * *
  1378. * OUTPUT: bool; Was the floating point number stored without error? *
  1379. * *
  1380. * WARNINGS: none *
  1381. * *
  1382. * HISTORY: *
  1383. * 8/27/2001 AJA : Created. *
  1384. *=============================================================================================*/
  1385. bool INIClass::Put_Double(char const * section, char const * entry, double number)
  1386. {
  1387. char buffer[MAX_LINE_LENGTH+1];
  1388. sprintf(buffer, "%lf", number);
  1389. return(Put_String(section, entry, buffer));
  1390. }
  1391. /***********************************************************************************************
  1392. * INIClass::Put_String -- Output a string to the section and entry specified. *
  1393. * *
  1394. * This routine will put an arbitrary string to the section and entry specified. Any *
  1395. * previous matching entry will be replaced. *
  1396. * *
  1397. * INPUT: section -- The section identifier to place the string under. *
  1398. * *
  1399. * entry -- The entry identifier to identify this string [placed under the section]*
  1400. * *
  1401. * string -- Pointer to the string to assign to this entry. *
  1402. * *
  1403. * OUTPUT: bool; Was the entry assigned without error? *
  1404. * *
  1405. * WARNINGS: none *
  1406. * *
  1407. * HISTORY: *
  1408. * 07/02/1996 JLB : Created. *
  1409. * 11/02/1996 JLB : Uses index handler. *
  1410. * 12/08/1997 EHC : Debug message for duplicate entries *
  1411. * 03/13/1998 NH : On duplicate CRC, check if strings identical. *
  1412. *=============================================================================================*/
  1413. bool INIClass::Put_String(char const * section, char const * entry, char const * string)
  1414. {
  1415. if (section == NULL || entry == NULL) return(false);
  1416. INISection * secptr = Find_Section(section);
  1417. if (secptr == NULL) {
  1418. secptr = new INISection(strdup(section));
  1419. if (secptr == NULL) return(false);
  1420. SectionList->Add_Tail(secptr);
  1421. SectionIndex->Add_Index(secptr->Index_ID(), secptr);
  1422. }
  1423. /*
  1424. ** Remove the old entry if found and print debug message
  1425. */
  1426. INIEntry * entryptr = secptr->Find_Entry(entry);
  1427. if (entryptr != NULL) {
  1428. if (strcmp(entryptr->Entry, entry)) {
  1429. DuplicateCRCError("INIClass::Put_String", section, entry);
  1430. } else {
  1431. OutputDebugString("INIClass::Put_String - Duplicate Entry \"");
  1432. OutputDebugString(entry);
  1433. OutputDebugString("\"\n");
  1434. }
  1435. secptr->EntryIndex.Remove_Index(entryptr->Index_ID());
  1436. delete entryptr;
  1437. }
  1438. /*
  1439. ** Create and add the new entry.
  1440. */
  1441. if (string != NULL && strlen(string) > 0) {
  1442. entryptr = new INIEntry(strdup(entry), strdup(string));
  1443. if (entryptr == NULL) {
  1444. return(false);
  1445. }
  1446. secptr->EntryList.Add_Tail(entryptr);
  1447. secptr->EntryIndex.Add_Index(entryptr->Index_ID(), entryptr);
  1448. }
  1449. return(true);
  1450. }
  1451. /***********************************************************************************************
  1452. * INIClass::Get_String -- Fetch the value of a particular entry in a specified section. *
  1453. * *
  1454. * This will retrieve the entire text to the right of the "=" character. The text is *
  1455. * found by finding a matching entry in the section specified. If no matching entry could *
  1456. * be found, then the default value will be stored in the output string buffer. *
  1457. * *
  1458. * INPUT: section -- Pointer to the section name to search under. *
  1459. * *
  1460. * entry -- The entry identifier to search for. *
  1461. * *
  1462. * defvalue -- If no entry could be found, then this text will be returned. *
  1463. * *
  1464. * buffer -- Output buffer to store the retrieved string into. *
  1465. * *
  1466. * size -- The size of the output buffer. The maximum string length that could *
  1467. * be retrieved will be one less than this length. This is due to the *
  1468. * forced trailing zero added to the end of the string. *
  1469. * *
  1470. * OUTPUT: Returns with the length of the string retrieved. *
  1471. * *
  1472. * WARNINGS: none *
  1473. * *
  1474. * HISTORY: *
  1475. * 07/02/1996 JLB : Created. *
  1476. *=============================================================================================*/
  1477. int INIClass::Get_String(char const * section, char const * entry, char const * defvalue, char * buffer, int size) const
  1478. {
  1479. /*
  1480. ** Verify that the parameters are nominally legal.
  1481. */
  1482. // if (buffer != NULL && size > 0) {
  1483. // buffer[0] = '\0';
  1484. // }
  1485. if (buffer == NULL || size < 2 || section == NULL || entry == NULL) return(0);
  1486. /*
  1487. ** Fetch the entry string if it is present. If not, then the normal default
  1488. ** value will be used as the entry value.
  1489. */
  1490. INIEntry * entryptr = Find_Entry(section, entry);
  1491. if (entryptr != NULL && entryptr->Value != NULL) {
  1492. defvalue = entryptr->Value;
  1493. }
  1494. /*
  1495. ** Fill in the buffer with the entry value and return with the length of the string.
  1496. */
  1497. if (defvalue == NULL) {
  1498. buffer[0] = '\0';
  1499. return(0);
  1500. } else {
  1501. strncpy(buffer, defvalue, size);
  1502. buffer[size-1] = '\0';
  1503. strtrim(buffer);
  1504. return(strlen(buffer));
  1505. }
  1506. }
  1507. /*
  1508. ** GetString
  1509. */
  1510. const StringClass& INIClass::Get_String(StringClass& new_string, char const * section, char const * entry, char const * defvalue) const
  1511. {
  1512. if (section == NULL || entry == NULL) {
  1513. new_string="";
  1514. return new_string;
  1515. }
  1516. /*
  1517. ** Fetch the entry string if it is present. If not, then the normal default
  1518. ** value will be used as the entry value.
  1519. */
  1520. INIEntry * entryptr = Find_Entry(section, entry);
  1521. if (entryptr != NULL) {
  1522. defvalue = entryptr->Value;
  1523. }
  1524. if (defvalue == NULL) {
  1525. new_string="";
  1526. return new_string;
  1527. }
  1528. new_string=defvalue;
  1529. return new_string;
  1530. }
  1531. /***********************************************************************************************
  1532. * INIClass::Get_String -- Fetch the value of a particular entry in a specified section. *
  1533. * *
  1534. * This will retrieve the entire text to the right of the "=" character. The text is *
  1535. * found by finding a matching entry in the section specified. If no matching entry could *
  1536. * be found, then the default value will be stored in the output string buffer. *
  1537. * *
  1538. * INPUT: section -- Pointer to the section name to search under. *
  1539. * *
  1540. * entry -- The entry identifier to search for. *
  1541. * *
  1542. * defvalue -- If no entry could be found, then this text will be returned. *
  1543. * *
  1544. * buffer -- Output buffer to store the retrieved string into. *
  1545. * *
  1546. * size -- The size of the output buffer. The maximum string length that could *
  1547. * be retrieved will be one less than this length. This is due to the *
  1548. * forced trailing zero added to the end of the string. *
  1549. * *
  1550. * OUTPUT: Returns with the length of the string retrieved. *
  1551. * *
  1552. * WARNINGS: none *
  1553. * *
  1554. * HISTORY: *
  1555. * 07/02/1996 JLB : Created. *
  1556. *=============================================================================================*/
  1557. char *INIClass::Get_Alloc_String(char const * section, char const * entry, char const * defvalue) const
  1558. {
  1559. if (section == NULL || entry == NULL) return(NULL);
  1560. /*
  1561. ** Fetch the entry string if it is present. If not, then the normal default
  1562. ** value will be used as the entry value.
  1563. */
  1564. INIEntry * entryptr = Find_Entry(section, entry);
  1565. if (entryptr != NULL) {
  1566. defvalue = entryptr->Value;
  1567. }
  1568. if (defvalue == NULL) return NULL;
  1569. return(strdup(defvalue));
  1570. }
  1571. int INIClass::Get_List_Index(char const * section, char const * entry, int const defvalue, char *list[])
  1572. {
  1573. if (section == NULL || entry == NULL) return(0);
  1574. INIEntry * entryptr = Find_Entry(section, entry);
  1575. if (entryptr == NULL || entryptr->Value == NULL) {
  1576. return defvalue;
  1577. }
  1578. for (int lp = 0; list[lp]; lp++) {
  1579. if (stricmp(entryptr->Value, list[lp]) == 0) {
  1580. return lp;
  1581. }
  1582. assert(lp < 1000);
  1583. }
  1584. return defvalue;
  1585. }
  1586. int INIClass::Get_Int_Bitfield(char const * section, char const * entry, int defvalue, char *list[])
  1587. {
  1588. // if we can't find the entry or the entry is null just return the default value
  1589. INIEntry * entryptr = Find_Entry(section, entry);
  1590. if (entryptr == NULL || entryptr->Value == NULL) {
  1591. return defvalue;
  1592. }
  1593. // swim through the entry breaking it down into its token pieces and
  1594. // get the bitfield value for each piece.
  1595. // int count = 0; (gth) initailized but not referenced...
  1596. int retval = 0;
  1597. char *str = strdup(entryptr->Value);
  1598. int lp;
  1599. for (char *token = strtok(str, "|+"); token; token = strtok(NULL, "|+")) {
  1600. for (lp = 0; list[lp]; lp++) {
  1601. // if this list entry matches our string token then we need
  1602. // to set this bit.
  1603. if (stricmp(token, list[lp]) == 0) {
  1604. retval |= (1 << lp);
  1605. break;
  1606. }
  1607. }
  1608. // if we reached the end of the list and found nothing then we need
  1609. // to assert since we have an unidentified value
  1610. if (list[lp] == NULL) assert(lp < 1000);
  1611. }
  1612. free(str);
  1613. return retval;
  1614. }
  1615. int * INIClass::Get_Alloc_Int_Array(char const * section, char const * entry, int listend)
  1616. {
  1617. int *retval = NULL;
  1618. INIEntry * entryptr = Find_Entry(section, entry);
  1619. if (entryptr == NULL || entryptr->Value == NULL) {
  1620. retval = new int[1];
  1621. retval[0] = listend;
  1622. return retval;
  1623. }
  1624. // count all the tokens in the string. Each token should represent an
  1625. // integer number.
  1626. int count = 0;
  1627. char *str = strdup(entryptr->Value);
  1628. char *token;
  1629. for (token = strtok(str, " "); token; token = strtok(NULL, " ")) {
  1630. count++;
  1631. }
  1632. free(str);
  1633. // now that we know how many tokens there are in the string, allocate a int
  1634. // array to hold the tokens and parse out the actual values.
  1635. retval = new int[count+1];
  1636. count = 0;
  1637. str = strdup(entryptr->Value);
  1638. for (token = strtok(str, " "); token; token = strtok(NULL, " ")) {
  1639. retval[count] = atoi(token);
  1640. count++;
  1641. }
  1642. free(str);
  1643. // arrays of integers are terminated with the listend variable passed in
  1644. retval[count] = listend;
  1645. // now that we have the allocated array with the results filled in lets return
  1646. // the results.
  1647. return retval;
  1648. }
  1649. /***********************************************************************************************
  1650. * INIClass::Put_Bool -- Store a boolean value into the INI database. *
  1651. * *
  1652. * Use this routine to place a boolean value into the INI database. The boolean value will *
  1653. * be stored as "yes" or "no". *
  1654. * *
  1655. * INPUT: section -- The section to place the entry and boolean value into. *
  1656. * *
  1657. * entry -- The entry identifier to tag to the boolean value. *
  1658. * *
  1659. * value -- The boolean value to place into the database. *
  1660. * *
  1661. * OUTPUT: bool; Was the boolean value placed into the database? *
  1662. * *
  1663. * WARNINGS: none *
  1664. * *
  1665. * HISTORY: *
  1666. * 07/03/1996 JLB : Created. *
  1667. *=============================================================================================*/
  1668. bool INIClass::Put_Bool(char const * section, char const * entry, bool value)
  1669. {
  1670. if (value) {
  1671. return(Put_String(section, entry, "yes"));
  1672. } else {
  1673. return(Put_String(section, entry, "no"));
  1674. }
  1675. }
  1676. /***********************************************************************************************
  1677. * INIClass::Get_Bool -- Fetch a boolean value for the section and entry specified. *
  1678. * *
  1679. * This routine will search under the section specified, looking for a matching entry. If *
  1680. * one is found, the value is interpreted as a boolean value and then returned. In the case *
  1681. * of no matching entry, the default value will be returned instead. The boolean value *
  1682. * is interpreted using the standard boolean conventions. e.g., "Yes", "Y", "1", "True", *
  1683. * "T" are all consider to be a TRUE boolean value. *
  1684. * *
  1685. * INPUT: section -- The section to search under. *
  1686. * *
  1687. * entry -- The entry to search for. *
  1688. * *
  1689. * defvalue -- The default value to use if no matching entry could be located. *
  1690. * *
  1691. * OUTPUT: Returns with the boolean value of the specified section and entry. If no match *
  1692. * then the default boolean value is returned. *
  1693. * *
  1694. * WARNINGS: none *
  1695. * *
  1696. * HISTORY: *
  1697. * 07/02/1996 JLB : Created. *
  1698. *=============================================================================================*/
  1699. bool INIClass::Get_Bool(char const * section, char const * entry, bool defvalue) const
  1700. {
  1701. /*
  1702. ** Verify that the parameters are nominally correct.
  1703. */
  1704. if (section == NULL || entry == NULL) return(defvalue);
  1705. INIEntry * entryptr = Find_Entry(section, entry);
  1706. if (entryptr && entryptr->Value != NULL) {
  1707. switch (toupper(*entryptr->Value)) {
  1708. case 'Y':
  1709. case 'T':
  1710. case '1':
  1711. return(true);
  1712. case 'N':
  1713. case 'F':
  1714. case '0':
  1715. return(false);
  1716. }
  1717. }
  1718. return(defvalue);
  1719. }
  1720. /***********************************************************************************************
  1721. * INIClass::Put_Point -- Store a point value to the database. *
  1722. * *
  1723. * This routine will store the point value to the INI database under the section and entry *
  1724. * specified. *
  1725. * *
  1726. * INPUT: section -- The name of the section to store the entry under. *
  1727. * *
  1728. * entry -- The entry to store the point data to. *
  1729. * *
  1730. * value -- The point value to store. *
  1731. * *
  1732. * OUTPUT: bool; Was the point value stored to the database? *
  1733. * *
  1734. * WARNINGS: none *
  1735. * *
  1736. * HISTORY: *
  1737. * 09/19/1997 JLB : Created. *
  1738. *=============================================================================================*/
  1739. bool INIClass::Put_Point(char const * section, char const * entry, TPoint2D<int> const & value)
  1740. {
  1741. char buffer[54];
  1742. sprintf(buffer, "%d,%d", value.X, value.Y);
  1743. return(Put_String(section, entry, buffer));
  1744. }
  1745. /***********************************************************************************************
  1746. * INIClass::Get_Point -- Fetch a point value from the INI database. *
  1747. * *
  1748. * This routine will retrieve a point value from the database by looking in the section and *
  1749. * entry specified. *
  1750. * *
  1751. * INPUT: section -- The name of the section to search for the entry under. *
  1752. * *
  1753. * entry -- The entry to search for. *
  1754. * *
  1755. * defvalue -- The default value to return if the section and entry were not found. *
  1756. * *
  1757. * OUTPUT: Returns with the point value retrieved from the database or the default value if *
  1758. * the section and entry were not found. *
  1759. * *
  1760. * WARNINGS: none *
  1761. * *
  1762. * HISTORY: *
  1763. * 09/19/1997 JLB : Created. *
  1764. *=============================================================================================*/
  1765. TPoint2D<int> const INIClass::Get_Point(char const * section, char const * entry, TPoint2D<int> const & defvalue) const
  1766. {
  1767. char buffer[64];
  1768. if (Get_String(section, entry, "", buffer, sizeof(buffer))) {
  1769. int x,y;
  1770. sscanf(buffer, "%d,%d", &x, &y);
  1771. return(TPoint2D<int>(x, y));
  1772. }
  1773. return(defvalue);
  1774. }
  1775. /***********************************************************************************************
  1776. * INIClass::Put_Point -- Stores a 3D point to the database. *
  1777. * *
  1778. * This routine will store the 3D point value to the database under the section and entry *
  1779. * specified. *
  1780. * *
  1781. * INPUT: section -- The name of the section that the entry will be stored under. *
  1782. * *
  1783. * entry -- The name of the entry that the point will be stored to. *
  1784. * *
  1785. * value -- The 3D point value to store. *
  1786. * *
  1787. * OUTPUT: bool; Was the point stored to the database? *
  1788. * *
  1789. * WARNINGS: none *
  1790. * *
  1791. * HISTORY: *
  1792. * 09/19/1997 JLB : Created. *
  1793. *=============================================================================================*/
  1794. bool INIClass::Put_Point(char const * section, char const * entry, TPoint3D<int> const & value)
  1795. {
  1796. char buffer[54];
  1797. sprintf(buffer, "%d,%d,%d", value.X, value.Y, value.Z);
  1798. return(Put_String(section, entry, buffer));
  1799. }
  1800. /***********************************************************************************************
  1801. * INIClass::Get_Point -- Fetch a 3D point from the database. *
  1802. * *
  1803. * This routine will retrieve a 3D point from the database from the section and entry *
  1804. * specified. *
  1805. * *
  1806. * INPUT: section -- The name of the section to search for th entry under. *
  1807. * *
  1808. * entry -- The name of the entry to search for. *
  1809. * *
  1810. * defvaule -- The default value to return if the section and entry could not be *
  1811. * found. *
  1812. * *
  1813. * OUTPUT: Returns with the 3D point from the database or the default value if the section *
  1814. * and entry could not be found. *
  1815. * *
  1816. * WARNINGS: none *
  1817. * *
  1818. * HISTORY: *
  1819. * 09/19/1997 JLB : Created. *
  1820. *=============================================================================================*/
  1821. TPoint3D<int> const INIClass::Get_Point(char const * section, char const * entry, TPoint3D<int> const & defvalue) const
  1822. {
  1823. char buffer[64];
  1824. if (Get_String(section, entry, "", buffer, sizeof(buffer))) {
  1825. int x,y,z;
  1826. sscanf(buffer, "%d,%d,%d", &x, &y, &z);
  1827. return(TPoint3D<int>(x, y, z));
  1828. }
  1829. return(defvalue);
  1830. }
  1831. /***********************************************************************************************
  1832. * INIClass::Put_Point -- Stores a 3D point to the database. *
  1833. * *
  1834. * This routine will store the 3D point value to the database under the section and entry *
  1835. * specified. *
  1836. * *
  1837. * INPUT: section -- The name of the section that the entry will be stored under. *
  1838. * *
  1839. * entry -- The name of the entry that the point will be stored to. *
  1840. * *
  1841. * value -- The 3D point value to store. *
  1842. * *
  1843. * OUTPUT: bool; Was the point stored to the database? *
  1844. * *
  1845. * WARNINGS: none *
  1846. * *
  1847. * HISTORY: *
  1848. * 09/19/1997 JLB : Created. *
  1849. *=============================================================================================*/
  1850. bool INIClass::Put_Point(char const * section, char const * entry, TPoint3D<float> const & value)
  1851. {
  1852. char buffer[54];
  1853. sprintf(buffer, "%f,%f,%f", (float)value.X, (float)value.Y, (float)value.Z);
  1854. return(Put_String(section, entry, buffer));
  1855. }
  1856. /***********************************************************************************************
  1857. * INIClass::Get_Point -- Fetch a 3D point from the database. *
  1858. * *
  1859. * This routine will retrieve a 3D point from the database from the section and entry *
  1860. * specified. *
  1861. * *
  1862. * INPUT: section -- The name of the section to search for th entry under. *
  1863. * *
  1864. * entry -- The name of the entry to search for. *
  1865. * *
  1866. * defvaule -- The default value to return if the section and entry could not be *
  1867. * found. *
  1868. * *
  1869. * OUTPUT: Returns with the 3D point from the database or the default value if the section *
  1870. * and entry could not be found. *
  1871. * *
  1872. * WARNINGS: none *
  1873. * *
  1874. * HISTORY: *
  1875. * 09/19/1997 JLB : Created. *
  1876. *=============================================================================================*/
  1877. TPoint3D<float> const INIClass::Get_Point(char const * section, char const * entry, TPoint3D<float> const & defvalue) const
  1878. {
  1879. char buffer[64];
  1880. if (Get_String(section, entry, "", buffer, sizeof(buffer))) {
  1881. float x,y,z;
  1882. sscanf(buffer, "%f,%f,%f", &x, &y, &z);
  1883. return(TPoint3D<float>(x, y, z));
  1884. }
  1885. return(defvalue);
  1886. }
  1887. /***********************************************************************************************
  1888. * INIClass::Get_Point -- Fetch a point value from the INI database. *
  1889. * *
  1890. * This routine will retrieve a point value from the database by looking in the section and *
  1891. * entry specified. *
  1892. * *
  1893. * INPUT: section -- The name of the section to search for the entry under. *
  1894. * *
  1895. * entry -- The entry to search for. *
  1896. * *
  1897. * defvalue -- The default value to return if the section and entry were not found. *
  1898. * *
  1899. * OUTPUT: Returns with the point value retrieved from the database or the default value if *
  1900. * the section and entry were not found. *
  1901. * *
  1902. * WARNINGS: none *
  1903. * *
  1904. * HISTORY: *
  1905. * 07/14/1999 NH : Created. *
  1906. *=============================================================================================*/
  1907. TPoint2D<float> const INIClass::Get_Point(char const * section, char const * entry, TPoint2D<float> const & defvalue) const
  1908. {
  1909. char buffer[64];
  1910. if (Get_String(section, entry, "", buffer, sizeof(buffer))) {
  1911. float x,y;
  1912. sscanf(buffer, "%f,%f", &x, &y);
  1913. return(TPoint2D<float>(x, y));
  1914. }
  1915. return(defvalue);
  1916. }
  1917. /***********************************************************************************************
  1918. * INISection::Find_Entry -- Finds a specified entry and returns pointer to it. *
  1919. * *
  1920. * This routine scans the supplied entry for the section specified. This is used for *
  1921. * internal database maintenance. *
  1922. * *
  1923. * INPUT: entry -- The entry to scan for. *
  1924. * *
  1925. * OUTPUT: Returns with a pointer to the entry control structure if the entry was found. *
  1926. * Otherwise it returns NULL. *
  1927. * *
  1928. * WARNINGS: none *
  1929. * *
  1930. * HISTORY: *
  1931. * 07/03/1996 JLB : Created. *
  1932. * 11/02/1996 JLB : Uses index handler. *
  1933. * 12/08/1997 EHC : Uses member CRC function
  1934. *=============================================================================================*/
  1935. INIEntry * INISection::Find_Entry(char const * entry) const
  1936. {
  1937. if (entry != NULL) {
  1938. // int crc = CRCEngine()(entry, strlen(entry));
  1939. int crc = CRC::String(entry);
  1940. if (EntryIndex.Is_Present(crc)) {
  1941. return(EntryIndex[crc]);
  1942. }
  1943. }
  1944. return(NULL);
  1945. }
  1946. /***********************************************************************************************
  1947. * INIClass::Put_PKey -- Stores the key to the INI database. *
  1948. * *
  1949. * The key stored to the database will have both the exponent and modulus portions saved. *
  1950. * Since the fast key only requires the modulus, it is only necessary to save the slow *
  1951. * key to the database. However, storing the slow key stores the information necessary to *
  1952. * generate the fast and slow keys. Because public key encryption requires one key to be *
  1953. * completely secure, only store the fast key in situations where the INI database will *
  1954. * be made public. *
  1955. * *
  1956. * INPUT: key -- The key to store the INI database. *
  1957. * *
  1958. * OUTPUT: bool; Was the key stored to the database? *
  1959. * *
  1960. * WARNINGS: Store the fast key for public INI database availability. Store the slow key if *
  1961. * the INI database is secure. *
  1962. * *
  1963. * HISTORY: *
  1964. * 07/08/1996 JLB : Created. *
  1965. *=============================================================================================*/
  1966. bool INIClass::Put_PKey(PKey const & key)
  1967. {
  1968. char buffer[512];
  1969. int len = key.Encode_Modulus(buffer);
  1970. Put_UUBlock("PublicKey", buffer, len);
  1971. len = key.Encode_Exponent(buffer);
  1972. Put_UUBlock("PrivateKey", buffer, len);
  1973. return(true);
  1974. }
  1975. /***********************************************************************************************
  1976. * INIClass::Get_PKey -- Fetch a key from the ini database. *
  1977. * *
  1978. * This routine will fetch the key from the INI database. The key fetched is controlled by *
  1979. * the parameter. There are two choices of key -- the fast or slow key. *
  1980. * *
  1981. * INPUT: fast -- Should the fast key be retrieved? The fast key has the advantage of *
  1982. * requiring only the modulus value. *
  1983. * *
  1984. * OUTPUT: Returns with the key retrieved. *
  1985. * *
  1986. * WARNINGS: none *
  1987. * *
  1988. * HISTORY: *
  1989. * 07/08/1996 JLB : Created. *
  1990. *=============================================================================================*/
  1991. PKey INIClass::Get_PKey(bool fast) const
  1992. {
  1993. PKey key;
  1994. char buffer[512];
  1995. /*
  1996. ** When retrieving the fast key, the exponent is a known constant. Don't parse the
  1997. ** exponent from the database.
  1998. */
  1999. if (fast) {
  2000. BigInt exp = PKey::Fast_Exponent();
  2001. exp.DEREncode((unsigned char *)buffer);
  2002. key.Decode_Exponent(buffer);
  2003. } else {
  2004. Get_UUBlock("PrivateKey", buffer, sizeof(buffer));
  2005. key.Decode_Exponent(buffer);
  2006. }
  2007. Get_UUBlock("PublicKey", buffer, sizeof(buffer));
  2008. key.Decode_Modulus(buffer);
  2009. return(key);
  2010. }
  2011. /***********************************************************************************************
  2012. * INIClass::Strip_Comments -- Strips comments of the specified text line. *
  2013. * *
  2014. * This routine will scan the string (text line) supplied and if any comment portions are *
  2015. * found, they will be trimmed off. Leading and trailing blanks are also removed. *
  2016. * *
  2017. * INPUT: buffer -- Pointer to the null terminate string to be processed. *
  2018. * *
  2019. * OUTPUT: none *
  2020. * *
  2021. * WARNINGS: none *
  2022. * *
  2023. * HISTORY: *
  2024. * 07/03/1996 JLB : Created. *
  2025. *=============================================================================================*/
  2026. void INIClass::Strip_Comments(char * buffer)
  2027. {
  2028. if (buffer != NULL) {
  2029. char * comment = strchr(buffer, ';');
  2030. if (comment) {
  2031. *comment = '\0';
  2032. strtrim(buffer);
  2033. }
  2034. }
  2035. }
  2036. /***********************************************************************************************
  2037. * INIClass::CRC - returns a (hopefully) unique 32-bit value for a string *
  2038. * *
  2039. * *
  2040. * *
  2041. * *
  2042. * INPUT: pointer to null terminated string *
  2043. * *
  2044. * OUTPUT: integer that is highly likely to be unique for a given INI file. *
  2045. * *
  2046. * WARNINGS: *
  2047. * *
  2048. * HISTORY: *
  2049. * 12/8/97 EHC : Created. *
  2050. *=============================================================================================*/
  2051. int INIClass::CRC(const char *string)
  2052. {
  2053. // simply call the CRC class string evaluator.
  2054. return CRC::String(string);
  2055. }
  2056. /***********************************************************************************************
  2057. * -- Displays debug information when a duplicate entry is found in an INI file *
  2058. * *
  2059. * *
  2060. * *
  2061. * *
  2062. * INPUT: message - text description of function with problem *
  2063. * entry - text buffer for duplicate entry name *
  2064. * OUTPUT: *
  2065. * *
  2066. * WARNINGS: will assert(0) and exit program. INI errors are considered fatal at this time. *
  2067. * *
  2068. * HISTORY: *
  2069. * 12/9/97 EHC : Created. *
  2070. * 8/27/2001 AJA : In Release mode under Windows, a message box will be displayed. *
  2071. *=============================================================================================*/
  2072. void INIClass::DuplicateCRCError(const char *message, const char *section, const char *entry)
  2073. {
  2074. char buffer[512];
  2075. _snprintf(buffer, sizeof(buffer), "%s - Duplicate Entry \"%s\" in section \"%s\" (%s)\n", message,
  2076. entry, section, Filename);
  2077. OutputDebugString(buffer);
  2078. assert(0);
  2079. #ifdef NDEBUG
  2080. #ifdef _WINDOWS
  2081. MessageBox(0, buffer, "Duplicate CRC in INI file.", MB_ICONSTOP | MB_OK);
  2082. #endif
  2083. #endif
  2084. }
  2085. void INIClass::Keep_Blank_Entries (bool keep_blanks)
  2086. {
  2087. KeepBlankEntries = keep_blanks;
  2088. }