ini.cpp 127 KB

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