ini.c 24 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265
  1. /**
  2. * WinPR: Windows Portable Runtime
  3. * .ini config file
  4. *
  5. * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
  6. *
  7. * Licensed under the Apache License, Version 2.0 (the "License");
  8. * you may not use this file except in compliance with the License.
  9. * You may obtain a copy of the License at
  10. *
  11. * http://www.apache.org/licenses/LICENSE-2.0
  12. *
  13. * Unless required by applicable law or agreed to in writing, software
  14. * distributed under the License is distributed on an "AS IS" BASIS,
  15. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  16. * See the License for the specific language governing permissions and
  17. * limitations under the License.
  18. */
  19. #ifdef HAVE_CONFIG_H
  20. #include "config.h"
  21. #endif
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #ifndef _WIN32
  26. #include <unistd.h>
  27. #endif
  28. #include <errno.h>
  29. #include <winpr/wtypes.h>
  30. #include <winpr/crt.h>
  31. #include <winpr/ini.h>
  32. #include "../log.h"
  33. #define TAG WINPR_TAG("ini")
  34. struct _wIniFileKey
  35. {
  36. char* name;
  37. char* value;
  38. BOOL invalid; /*extend */
  39. };
  40. typedef struct _wIniFileKey wIniFileKey;
  41. struct _wIniFileSection
  42. {
  43. char* name;
  44. size_t nKeys;
  45. size_t cKeys;
  46. wIniFileKey** keys;
  47. BOOL invalid; /*extend */
  48. };
  49. typedef struct _wIniFileSection wIniFileSection;
  50. struct _wIniFile
  51. {
  52. FILE* fp;
  53. char* line;
  54. char* nextLine;
  55. size_t lineLength;
  56. char* tokctx;
  57. char* buffer;
  58. char* filename;
  59. BOOL readOnly;
  60. size_t nSections;
  61. size_t cSections;
  62. wIniFileSection** sections;
  63. };
  64. static BOOL IniFile_Load_NextLine(wIniFile* ini, char* str)
  65. {
  66. size_t length = 0;
  67. still: // fix \r\n gifur
  68. ini->nextLine = strtok_s(str, "\n", &ini->tokctx);
  69. if (ini->nextLine)
  70. length = strlen(ini->nextLine);
  71. if (length > 0)
  72. {
  73. if (ini->nextLine[length - 1] == '\r')
  74. {
  75. ini->nextLine[length - 1] = '\0';
  76. length--;
  77. }
  78. if (length < 1) { // must be zero !!
  79. if(strlen(ini->tokctx) > 0) {
  80. goto still;
  81. }else {
  82. ini->nextLine = NULL;
  83. }
  84. }
  85. }
  86. return (ini->nextLine) ? TRUE : FALSE;
  87. }
  88. static BOOL IniFile_Load_String(wIniFile* ini, const char* iniString)
  89. {
  90. size_t fileSize;
  91. if (!ini || !iniString)
  92. return FALSE;
  93. ini->line = NULL;
  94. ini->nextLine = NULL;
  95. ini->buffer = NULL;
  96. fileSize = strlen(iniString);
  97. if (fileSize < 1)
  98. return FALSE;
  99. ini->buffer = (char*)malloc(fileSize + 2);
  100. if (!ini->buffer)
  101. return FALSE;
  102. CopyMemory(ini->buffer, iniString, fileSize);
  103. ini->buffer[fileSize] = '\n';
  104. ini->buffer[fileSize + 1] = '\0';
  105. IniFile_Load_NextLine(ini, ini->buffer);
  106. return TRUE;
  107. }
  108. /*fopen*/
  109. static BOOL IniFile_Open_File(wIniFile* ini, const char* filename)
  110. {
  111. if (!ini || !filename)
  112. return FALSE;
  113. if (ini->readOnly)
  114. ini->fp = fopen(filename, "rb");
  115. else
  116. ini->fp = fopen(filename, "w+b");
  117. if (!ini->fp)
  118. return FALSE;
  119. return TRUE;
  120. }
  121. /**/
  122. static BOOL IniFile_Load_File(wIniFile* ini, const char* filename)
  123. {
  124. INT64 fileSize;
  125. if (!IniFile_Open_File(ini, filename))
  126. return FALSE;
  127. if (_fseeki64(ini->fp, 0, SEEK_END) < 0)
  128. goto out_file;
  129. fileSize = _ftelli64(ini->fp);
  130. if (fileSize < 0)
  131. goto out_file;
  132. if (_fseeki64(ini->fp, 0, SEEK_SET) < 0)
  133. goto out_file;
  134. ini->line = NULL;
  135. ini->nextLine = NULL;
  136. ini->buffer = NULL;
  137. if (fileSize < 1)
  138. goto out_file;
  139. ini->buffer = (char*)malloc((size_t)fileSize + 2);
  140. if (!ini->buffer)
  141. goto out_file;
  142. if (fread(ini->buffer, (size_t)fileSize, 1, ini->fp) != 1)
  143. goto out_buffer;
  144. fclose(ini->fp);
  145. ini->fp = NULL;
  146. ini->buffer[fileSize] = '\n';
  147. ini->buffer[fileSize + 1] = '\0';
  148. IniFile_Load_NextLine(ini, ini->buffer);
  149. return TRUE;
  150. out_buffer:
  151. free(ini->buffer);
  152. ini->buffer = NULL;
  153. out_file:
  154. fclose(ini->fp);
  155. ini->fp = NULL;
  156. return FALSE;
  157. }
  158. static void IniFile_Load_Finish(wIniFile* ini)
  159. {
  160. if (!ini)
  161. return;
  162. if (ini->buffer)
  163. {
  164. free(ini->buffer);
  165. ini->buffer = NULL;
  166. }
  167. }
  168. static BOOL IniFile_Load_HasNextLine(wIniFile* ini)
  169. {
  170. if (!ini)
  171. return FALSE;
  172. return (ini->nextLine) ? TRUE : FALSE;
  173. }
  174. static char* IniFile_Load_GetNextLine(wIniFile* ini)
  175. {
  176. if (!ini)
  177. return NULL;
  178. ini->line = ini->nextLine;
  179. ini->lineLength = strlen(ini->line);
  180. IniFile_Load_NextLine(ini, NULL);
  181. return ini->line;
  182. }
  183. static wIniFileKey* IniFile_Key_New(const char* name, const char* value)
  184. {
  185. wIniFileKey* key;
  186. if (!name || !value)
  187. return NULL;
  188. key = malloc(sizeof(wIniFileKey));
  189. if (key)
  190. {
  191. key->name = _strdup(name);
  192. key->value = _strdup(value);
  193. key->invalid = FALSE;
  194. if (!key->name || !key->value)
  195. {
  196. free(key->name);
  197. free(key->value);
  198. free(key);
  199. return NULL;
  200. }
  201. }
  202. return key;
  203. }
  204. static void IniFile_Key_Free(wIniFileKey* key)
  205. {
  206. if (!key)
  207. return;
  208. free(key->name);
  209. free(key->value);
  210. free(key);
  211. }
  212. static wIniFileSection* IniFile_Section_New(const char* name)
  213. {
  214. wIniFileSection* section;
  215. if (!name)
  216. return NULL;
  217. section = malloc(sizeof(wIniFileSection));
  218. if (!section)
  219. return NULL;
  220. section->name = _strdup(name);
  221. if (!section->name)
  222. {
  223. free(section);
  224. return NULL;
  225. }
  226. section->invalid = FALSE;
  227. section->nKeys = 0;
  228. section->cKeys = 64;
  229. section->keys = (wIniFileKey**)calloc(section->cKeys, sizeof(wIniFileKey*));
  230. if (!section->keys)
  231. {
  232. free(section->name);
  233. free(section);
  234. return NULL;
  235. }
  236. return section;
  237. }
  238. static void IniFile_Section_Free(wIniFileSection* section)
  239. {
  240. size_t index;
  241. if (!section)
  242. return;
  243. free(section->name);
  244. for (index = 0; index < section->nKeys; index++)
  245. {
  246. IniFile_Key_Free(section->keys[index]);
  247. }
  248. free(section->keys);
  249. free(section);
  250. }
  251. static wIniFileSection* IniFile_GetSection(wIniFile* ini, const char* name)
  252. {
  253. size_t index;
  254. wIniFileSection* section = NULL;
  255. if (!ini || !name)
  256. return NULL;
  257. for (index = 0; index < ini->nSections; index++)
  258. {
  259. if (_stricmp(name, ini->sections[index]->name) == 0
  260. && !ini->sections[index]->invalid)
  261. {
  262. section = ini->sections[index];
  263. break;
  264. }
  265. }
  266. return section;
  267. }
  268. static wIniFileSection* IniFile_AddSection(wIniFile* ini, const char* name)
  269. {
  270. wIniFileSection* section;
  271. if (!ini || !name)
  272. return NULL;
  273. section = IniFile_GetSection(ini, name);
  274. if (!section)
  275. {
  276. if ((ini->nSections + 1) >= (ini->cSections))
  277. {
  278. size_t new_size;
  279. wIniFileSection** new_sect;
  280. new_size = ini->cSections * 2;
  281. new_sect = (wIniFileSection**)realloc(ini->sections, sizeof(wIniFileSection*) * new_size);
  282. if (!new_sect)
  283. return NULL;
  284. ini->cSections = new_size;
  285. ini->sections = new_sect;
  286. }
  287. section = IniFile_Section_New(name);
  288. ini->sections[ini->nSections] = section;
  289. ini->nSections++;
  290. }
  291. return section;
  292. }
  293. static BOOL IniFile_RemoveSection(wIniFile* ini, const char* name, BOOL* changed)
  294. {
  295. size_t index;
  296. wIniFileSection* section = NULL;
  297. if (!ini || !name)
  298. return FALSE;
  299. for (index = 0; index < ini->nSections; index++) {
  300. if (_stricmp(name, ini->sections[index]->name) == 0) {
  301. section = ini->sections[index];
  302. break;
  303. }
  304. }
  305. if(section)
  306. {
  307. ini->nSections--;
  308. ini->sections[index] = ini->sections[ini->nSections];
  309. ini->sections[ini->nSections] = NULL;
  310. IniFile_Section_Free(section);
  311. if(changed)
  312. {
  313. *changed = TRUE;
  314. }
  315. }
  316. return TRUE;
  317. }
  318. static wIniFileKey* IniFile_GetKey(wIniFile* ini, wIniFileSection* section, const char* name)
  319. {
  320. size_t index;
  321. wIniFileKey* key = NULL;
  322. if (!ini || !section || !name)
  323. return NULL;
  324. for (index = 0; index < section->nKeys; index++)
  325. {
  326. if (_stricmp(name, section->keys[index]->name) == 0)
  327. {
  328. key = section->keys[index];
  329. break;
  330. }
  331. }
  332. return key;
  333. }
  334. static wIniFileKey* IniFile_AddKey(wIniFile* ini, wIniFileSection* section, const char* name,
  335. const char* value, BOOL* changed)
  336. {
  337. wIniFileKey* key;
  338. if (!section || !name || !value)
  339. return NULL;
  340. key = IniFile_GetKey(ini, section, name);
  341. if (!key)
  342. {
  343. if ((section->nKeys + 1) >= (section->cKeys))
  344. {
  345. size_t new_size;
  346. wIniFileKey** new_key;
  347. new_size = section->cKeys * 2;
  348. new_key = (wIniFileKey**)realloc(section->keys, sizeof(wIniFileKey*) * new_size);
  349. if (!new_key)
  350. return NULL;
  351. section->cKeys = new_size;
  352. section->keys = new_key;
  353. }
  354. key = IniFile_Key_New(name, value);
  355. if (!key)
  356. return NULL;
  357. section->keys[section->nKeys] = key;
  358. section->nKeys++;
  359. if (changed) { *changed = TRUE; }
  360. }
  361. else if(_stricmp(key->value, value) != 0)
  362. {
  363. free(key->value);
  364. key->value = _strdup(value);
  365. if (!key->value)
  366. return NULL;
  367. if (changed) { *changed = TRUE; }
  368. }
  369. return key;
  370. }
  371. static BOOL IniFile_RemoveKey(wIniFile* ini, const char* sectionName, const char* keyName, BOOL* changed)
  372. {
  373. size_t index;
  374. wIniFileKey* key = NULL;
  375. wIniFileSection* section = NULL;
  376. if (!sectionName || !keyName)
  377. return FALSE;
  378. section = IniFile_GetSection(ini, sectionName);
  379. if(section)
  380. {
  381. for (index = 0; index < section->nKeys; index++) {
  382. if (_stricmp(keyName, section->keys[index]->name) == 0) {
  383. key = section->keys[index];
  384. break;
  385. }
  386. }
  387. if(key)
  388. {
  389. section->nKeys--;
  390. section->keys[index] = section->keys[section->nKeys];
  391. section->keys[section->nKeys] = NULL;
  392. IniFile_Key_Free(key);
  393. if(changed)
  394. {
  395. *changed = TRUE;
  396. }
  397. }
  398. }
  399. return TRUE;
  400. }
  401. static int IniFile_Load(wIniFile* ini)
  402. {
  403. char* line;
  404. char* name;
  405. char* value;
  406. char* separator;
  407. char *beg, *end;
  408. wIniFileSection* section = NULL;
  409. if (!ini)
  410. return -1;
  411. while (IniFile_Load_HasNextLine(ini))
  412. {
  413. line = IniFile_Load_GetNextLine(ini);
  414. if (line[0] == ';' || line[0] == '#')
  415. continue;
  416. if (line[0] == '[')
  417. {
  418. beg = &line[1];
  419. end = strchr(line, ']');
  420. if (!end) {
  421. fprintf(stderr, "parse line \"%s\" with [ failed.\n", line);
  422. return -1;
  423. }
  424. *end = '\0';
  425. IniFile_AddSection(ini, beg);
  426. section = ini->sections[ini->nSections - 1];
  427. }
  428. else
  429. {
  430. separator = strchr(line, '=');
  431. if (separator == NULL) {
  432. fprintf(stderr, "parse line \"%s\" with = failed.\n", line);
  433. return -1;
  434. }
  435. end = separator;
  436. while ((&end[-1] > line) && ((end[-1] == ' ') || (end[-1] == '\t')))
  437. end--;
  438. *end = '\0';
  439. name = line;
  440. beg = separator + 1;
  441. while (*beg && ((*beg == ' ') || (*beg == '\t')))
  442. beg++;
  443. if (*beg == '"')
  444. beg++;
  445. end = &line[ini->lineLength];
  446. while ((end > beg) && ((end[-1] == ' ') || (end[-1] == '\t')))
  447. end--;
  448. if (end[-1] == '"')
  449. end[-1] = '\0';
  450. value = beg;
  451. if (!IniFile_AddKey(ini, section, name, value, NULL)) {
  452. fprintf(stderr, "IniFile_AddKey \"%s\" with %s=%s failed.\n", section->name, name, value);
  453. return -1;
  454. }
  455. }
  456. }
  457. IniFile_Load_Finish(ini);
  458. return 1;
  459. }
  460. int IniFile_ReadBuffer(wIniFile* ini, const char* buffer)
  461. {
  462. BOOL status;
  463. if (!ini || !buffer)
  464. return -1;
  465. ini->readOnly = TRUE;
  466. ini->filename = NULL;
  467. status = IniFile_Load_String(ini, buffer);
  468. if (!status)
  469. return -1;
  470. return IniFile_Load(ini);
  471. }
  472. int IniFile_ReadFile(wIniFile* ini, const char* filename)
  473. {
  474. ini->readOnly = TRUE;
  475. free(ini->filename);
  476. ini->filename = _strdup(filename);
  477. if (!ini->filename)
  478. return -1;
  479. if (!IniFile_Load_File(ini, filename))
  480. return -1;
  481. return IniFile_Load(ini);
  482. }
  483. char** IniFile_GetSectionNames(wIniFile* ini, int* count)
  484. {
  485. char* p;
  486. size_t index;
  487. size_t length;
  488. size_t nameLength;
  489. char** sectionNames;
  490. wIniFileSection* section = NULL;
  491. if (!ini || !count)
  492. return NULL;
  493. if (ini->nSections > INT_MAX)
  494. return NULL;
  495. length = (sizeof(char*) * ini->nSections) + sizeof(char);
  496. for (index = 0; index < ini->nSections; index++)
  497. {
  498. section = ini->sections[index];
  499. nameLength = strlen(section->name);
  500. length += (nameLength + 1);
  501. }
  502. sectionNames = (char**)malloc(length);
  503. if (!sectionNames)
  504. return NULL;
  505. p = (char*)&((BYTE*)sectionNames)[sizeof(char*) * ini->nSections];
  506. for (index = 0; index < ini->nSections; index++)
  507. {
  508. sectionNames[index] = p;
  509. section = ini->sections[index];
  510. nameLength = strlen(section->name);
  511. CopyMemory(p, section->name, nameLength + 1);
  512. p += (nameLength + 1);
  513. }
  514. *p = '\0';
  515. *count = (int)ini->nSections;
  516. return sectionNames;
  517. }
  518. char** IniFile_GetSectionKeyNames(wIniFile* ini, const char* section, int* count)
  519. {
  520. char* p;
  521. size_t index;
  522. size_t length;
  523. size_t nameLength;
  524. char** keyNames;
  525. wIniFileKey* pKey = NULL;
  526. wIniFileSection* pSection = NULL;
  527. if (!ini || !section || !count)
  528. return NULL;
  529. pSection = IniFile_GetSection(ini, section);
  530. if (!pSection)
  531. return NULL;
  532. if (pSection->nKeys > INT_MAX)
  533. return NULL;
  534. length = (sizeof(char*) * pSection->nKeys) + sizeof(char);
  535. for (index = 0; index < pSection->nKeys; index++)
  536. {
  537. pKey = pSection->keys[index];
  538. nameLength = strlen(pKey->name);
  539. length += (nameLength + 1);
  540. }
  541. keyNames = (char**)malloc(length);
  542. if (!keyNames)
  543. return NULL;
  544. p = (char*)&((BYTE*)keyNames)[sizeof(char*) * pSection->nKeys];
  545. for (index = 0; index < pSection->nKeys; index++)
  546. {
  547. keyNames[index] = p;
  548. pKey = pSection->keys[index];
  549. nameLength = strlen(pKey->name);
  550. CopyMemory(p, pKey->name, nameLength + 1);
  551. p += (nameLength + 1);
  552. }
  553. *p = '\0';
  554. *count = (int)pSection->nKeys;
  555. return keyNames;
  556. }
  557. const char* IniFile_GetKeyValueString(wIniFile* ini, const char* section, const char* key)
  558. {
  559. const char* value = NULL;
  560. wIniFileKey* pKey = NULL;
  561. wIniFileSection* pSection = NULL;
  562. pSection = IniFile_GetSection(ini, section);
  563. if (!pSection)
  564. return NULL;
  565. pKey = IniFile_GetKey(ini, pSection, key);
  566. if (!pKey)
  567. return NULL;
  568. value = (const char*)pKey->value;
  569. return value;
  570. }
  571. int IniFile_GetKeyValueInt(wIniFile* ini, const char* section, const char* key, const int defValue)
  572. {
  573. int err;
  574. long value = 0;
  575. wIniFileKey* pKey = NULL;
  576. wIniFileSection* pSection = NULL;
  577. pSection = IniFile_GetSection(ini, section);
  578. if (!pSection)
  579. return defValue;
  580. pKey = IniFile_GetKey(ini, pSection, key);
  581. if (!pKey)
  582. return defValue;
  583. err = errno;
  584. errno = 0;
  585. value = strtol(pKey->value, NULL, 0);
  586. if ((value < INT_MIN) || (value > INT_MAX) || (errno != 0))
  587. {
  588. errno = err;
  589. return defValue;
  590. }
  591. return (int)value;
  592. }
  593. int IniFile_SetKeyValueString(wIniFile* ini, const char* section, const char* key,
  594. const char* value)
  595. {
  596. wIniFileKey* pKey = NULL;
  597. wIniFileSection* pSection = NULL;
  598. pSection = IniFile_GetSection(ini, section);
  599. if (!pSection)
  600. pSection = IniFile_AddSection(ini, section);
  601. if (!pSection)
  602. return -1;
  603. pKey = IniFile_AddKey(ini, pSection, key, value, NULL);
  604. if (!pKey)
  605. return -1;
  606. return 1;
  607. }
  608. int IniFile_SetKeyValueInt(wIniFile* ini, const char* section, const char* key, int value)
  609. {
  610. char strVal[128];
  611. wIniFileKey* pKey = NULL;
  612. wIniFileSection* pSection = NULL;
  613. sprintf_s(strVal, sizeof(strVal), "%d", value);
  614. pSection = IniFile_GetSection(ini, section);
  615. if (!pSection)
  616. pSection = IniFile_AddSection(ini, section);
  617. if (!pSection)
  618. return -1;
  619. pKey = IniFile_AddKey(ini, pSection, key, strVal, NULL);
  620. if (!pKey)
  621. return -1;
  622. return 1;
  623. }
  624. char* IniFile_WriteBuffer(wIniFile* ini)
  625. {
  626. size_t i, j;
  627. size_t offset;
  628. size_t size;
  629. char* buffer;
  630. wIniFileKey* key;
  631. wIniFileSection* section;
  632. size = 0;
  633. if (!ini)
  634. return NULL;
  635. /*calculate the rquired buffer size for storing*/
  636. for (i = 0; i < ini->nSections; i++)
  637. {
  638. section = ini->sections[i];
  639. size += (strlen(section->name) + 3);
  640. for (j = 0; j < section->nKeys; j++)
  641. {
  642. key = section->keys[j];
  643. size += (strlen(key->name) + strlen(key->value) + 2);
  644. }
  645. size += 1;
  646. }
  647. /*allocate buffer*/
  648. size += 1;
  649. buffer = malloc(size + 1);
  650. if (!buffer)
  651. return NULL;
  652. offset = 0;
  653. /*write to the buffer*/
  654. for (i = 0; i < ini->nSections; i++)
  655. {
  656. section = ini->sections[i];
  657. sprintf_s(&buffer[offset], size - offset, "[%s]\n", section->name);
  658. offset += (strlen(section->name) + 3);
  659. for (j = 0; j < section->nKeys; j++)
  660. {
  661. key = section->keys[j];
  662. sprintf_s(&buffer[offset], size - offset, "%s=%s\n", key->name, key->value);
  663. offset += (strlen(key->name) + strlen(key->value) + 2);
  664. }
  665. sprintf_s(&buffer[offset], size - offset, "\n");
  666. offset += 1;
  667. }
  668. buffer[offset] = '\0';
  669. return buffer;
  670. }
  671. int IniFile_WriteFile(wIniFile* ini, const char* filename)
  672. {
  673. size_t length;
  674. char* buffer;
  675. int ret = 1;
  676. buffer = IniFile_WriteBuffer(ini);
  677. if (!buffer)
  678. return -1;
  679. length = strlen(buffer);
  680. /*set write flag*/
  681. ini->readOnly = FALSE;
  682. if (!filename)
  683. filename = ini->filename;
  684. if (!IniFile_Open_File(ini, filename))
  685. {
  686. free(buffer);
  687. return -1;
  688. }
  689. if (fwrite((void*)buffer, length, 1, ini->fp) != 1)
  690. ret = -1;
  691. fclose(ini->fp);
  692. free(buffer);
  693. return ret;
  694. }
  695. wIniFile* IniFile_New(void)
  696. {
  697. wIniFile* ini = (wIniFile*)calloc(1, sizeof(wIniFile));
  698. if (ini)
  699. {
  700. ini->nSections = 0;
  701. ini->cSections = 64;
  702. ini->sections = (wIniFileSection**)calloc(ini->cSections, sizeof(wIniFileSection*));
  703. if (!ini->sections)
  704. {
  705. free(ini);
  706. return NULL;
  707. }
  708. }
  709. return ini;
  710. }
  711. void IniFile_Free(wIniFile* ini)
  712. {
  713. size_t index;
  714. if (!ini)
  715. return;
  716. free(ini->filename);
  717. for (index = 0; index < ini->nSections; index++)
  718. IniFile_Section_Free(ini->sections[index]);
  719. free(ini->sections);
  720. free(ini);
  721. }
  722. #ifndef _WIN32
  723. DWORD GetPrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpDefault,
  724. LPSTR lpReturnedString, DWORD nSize, LPCSTR lpFileName)
  725. {
  726. wIniFile* ini;
  727. DWORD nRetSize = 0;
  728. DWORD nRealSize = 0;
  729. const char* value;
  730. wIniFileSection* pSection = NULL;
  731. int index;
  732. wIniFileKey* key = NULL;
  733. char *t;
  734. size_t totalLen = 0;
  735. if(lpAppName == NULL)
  736. {
  737. return GetPrivateProfileSectionNamesA(lpReturnedString, nSize, lpFileName);
  738. }
  739. ini = IniFile_New();
  740. if(IniFile_ReadFile(ini, lpFileName) < 0) {
  741. IniFile_Free(ini);
  742. WLog_ERR(TAG, "failed to parse %s", lpFileName);
  743. return 0;
  744. }
  745. if(lpKeyName != NULL) {
  746. value = IniFile_GetKeyValueString(ini, lpAppName, lpKeyName);
  747. if(value) {
  748. nRealSize = strlen(value);
  749. if(nRealSize +1 > nSize)
  750. {
  751. nRetSize = nSize - 1;
  752. }
  753. else
  754. {
  755. if (nSize > 0 && lpReturnedString) {
  756. strncpy(lpReturnedString, value, strlen(value) + 1);
  757. }
  758. nRetSize = nRealSize;
  759. }
  760. }
  761. } else { // key == null
  762. pSection = IniFile_GetSection(ini, lpAppName);
  763. if (pSection) {
  764. totalLen = 0;
  765. for (index = 0; index < pSection->nKeys; index++) {
  766. key = pSection->keys[index];
  767. if(strlen(key->name) > 0)
  768. totalLen += strlen(key->name) + 1;
  769. }
  770. totalLen++;
  771. // if(totalLen > 0) {
  772. // totalLen--;
  773. // }
  774. nRealSize = nRetSize = totalLen;
  775. if(totalLen > 1 && nSize >= 2 && lpReturnedString) {
  776. if(totalLen > nSize) {
  777. // for compatible the upper invoke
  778. nRetSize = nSize - 2;
  779. } else {
  780. char* temp = malloc(sizeof(char)*totalLen);
  781. if(temp) {
  782. memset(temp, 0, sizeof(char)*totalLen);
  783. t = temp;
  784. for (index = 0; index < pSection->nKeys; index++) {
  785. key = pSection->keys[index];
  786. if(strcmp(key->name, "InitiativeTransfer") == 0) {
  787. ;
  788. }
  789. if(strlen(key->name) > 0) {
  790. strcpy(t, key->name);
  791. t += strlen(key->name);
  792. *t = '\0';
  793. t++;
  794. }
  795. }
  796. *t = '\0';
  797. totalLen = nSize > totalLen ? totalLen : nSize;
  798. memcpy(lpReturnedString, temp, sizeof(char)*totalLen);
  799. free(temp);
  800. }
  801. }
  802. }
  803. }
  804. }
  805. if(nRealSize == 0 && nSize > 0 && lpReturnedString) {
  806. lpReturnedString[0] = '\0';
  807. if(lpDefault) {
  808. nRealSize = nSize > strlen(lpDefault)+1 ? strlen(lpDefault)+1 : nSize;
  809. strncpy(lpReturnedString, lpDefault, nRealSize);
  810. nRetSize = strlen(lpReturnedString);
  811. }
  812. }
  813. IniFile_Free(ini);
  814. return nRetSize;
  815. }
  816. DWORD GetPrivateProfileStringW(LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpDefault,
  817. LPWSTR lpReturnedString, DWORD nSize, LPCWSTR lpFileName)
  818. {
  819. WLog_ERR(TAG, "%s operation not implemented", __FUNCTION__);
  820. return FALSE;
  821. }
  822. UINT GetPrivateProfileIntA(LPCSTR lpAppName, LPCSTR lpKeyName, INT nDefault, LPCSTR lpFileName)
  823. {
  824. UINT ret = nDefault;
  825. wIniFile* ini;
  826. ini = IniFile_New();
  827. if(!ini) {
  828. return ret;
  829. }
  830. if(IniFile_ReadFile(ini, lpFileName) < 0) {
  831. IniFile_Free(ini);
  832. WLog_ERR(TAG, "failed to parse %s", lpFileName);
  833. return ret;
  834. }
  835. ret = IniFile_GetKeyValueInt(ini, lpAppName, lpKeyName, nDefault);
  836. IniFile_Free(ini);
  837. return ret;
  838. }
  839. UINT GetPrivateProfileIntW(LPCWSTR lpAppName, LPCWSTR lpKeyName, INT nDefault, LPCWSTR lpFileName)
  840. {
  841. WLog_ERR(TAG, "%s operation not implemented", __FUNCTION__);
  842. return FALSE;
  843. }
  844. DWORD GetPrivateProfileSectionNamesA(LPSTR lpszReturnBuffer, DWORD nSize, LPCSTR lpFileName)
  845. {
  846. DWORD ret = 0;
  847. wIniFile* ini;
  848. int index;
  849. int length;
  850. int validCount = 0;
  851. int nameLength;
  852. char* sectionNames;
  853. wIniFileSection* section = NULL;
  854. char *p;
  855. ini = IniFile_New();
  856. if(!ini) {
  857. return ret;
  858. }
  859. if(IniFile_ReadFile(ini, lpFileName) < 0) {
  860. IniFile_Free(ini);
  861. WLog_ERR(TAG, "failed to parse %s", lpFileName);
  862. return ret;
  863. }
  864. length = 0;
  865. for (index = 0; index < ini->nSections; index++) {
  866. section = ini->sections[index];
  867. if(section->invalid) {
  868. continue;
  869. }
  870. validCount++;
  871. nameLength = (int) strlen(section->name);
  872. length += (nameLength + 1);
  873. }
  874. length++;
  875. sectionNames = (char*)malloc(length);
  876. if (!sectionNames)
  877. return ret;
  878. p = sectionNames;
  879. for (index = 0; index < ini->nSections; index++)
  880. {
  881. section = ini->sections[index];
  882. if(section->invalid) {
  883. continue;
  884. }
  885. nameLength = (int) strlen(section->name);
  886. CopyMemory(p, section->name, nameLength + 1);
  887. p += (nameLength + 1);
  888. }
  889. *p = '\0';
  890. ret = length;
  891. if(lpszReturnBuffer != NULL && nSize > 0) {
  892. if(nSize < length) {
  893. ret = nSize - 2;
  894. } else {
  895. CopyMemory(lpszReturnBuffer, sectionNames, length);
  896. }
  897. }
  898. if(sectionNames != NULL) {
  899. free(sectionNames);
  900. }
  901. IniFile_Free(ini);
  902. return ret;
  903. }
  904. DWORD GetPrivateProfileSectionNamesW(LPWSTR lpszReturnBuffer, DWORD nSize, LPCWSTR lpFileName)
  905. {
  906. WLog_ERR(TAG, "%s operation not implemented", __FUNCTION__);
  907. return FALSE;
  908. }
  909. BOOL WritePrivateProfileStringA(LPCSTR lpAppName, LPCSTR lpKeyName, LPCSTR lpString, LPCSTR lpFileName)
  910. {
  911. wIniFile* ini;
  912. BOOL ret = TRUE;
  913. BOOL changed = FALSE;
  914. ini = IniFile_New();
  915. if(!ini) {
  916. return FALSE;
  917. }
  918. if(IniFile_ReadFile(ini, lpFileName) < 0 && access(lpFileName, F_OK) == 0) {
  919. printf("open ini file failed.\n");
  920. ret = FALSE;
  921. } else {
  922. if(lpAppName == NULL)
  923. {
  924. //TODO:
  925. }
  926. if(lpKeyName == NULL)
  927. {
  928. //remove all entries inner section and the section also.
  929. ret = IniFile_RemoveSection(ini, lpAppName, &changed);
  930. }
  931. else if(lpString == NULL)
  932. {
  933. //remote the specified entry inner section
  934. ret = IniFile_RemoveKey(ini, lpAppName, lpKeyName, &changed);
  935. }
  936. else
  937. {
  938. if (IniFile_SetKeyValueString(ini, lpAppName, lpKeyName, lpString) < 0) {
  939. ret = FALSE;
  940. } else
  941. {
  942. changed = TRUE;
  943. }
  944. }
  945. }
  946. finished:
  947. if(ret && changed)
  948. {
  949. if (IniFile_WriteFile(ini, lpFileName) < 0) {
  950. ret = FALSE;
  951. }
  952. }
  953. IniFile_Free(ini);
  954. return ret;
  955. }
  956. BOOL WritePrivateProfileStringW(LPCWSTR lpAppName, LPCWSTR lpKeyName, LPCWSTR lpString, LPCWSTR lpFileName)
  957. {
  958. WLog_ERR(TAG, "%s operation not implemented", __FUNCTION__);
  959. return FALSE;
  960. }
  961. BOOL WritePrivateProfileSectionA(LPCSTR lpAppName, LPCSTR lpString, LPCSTR lpFileName)
  962. {
  963. wIniFile* ini;
  964. BOOL ret = TRUE;
  965. BOOL changed = FALSE;
  966. wIniFileSection* pSection = NULL;
  967. wIniFileKey* pKey = NULL;
  968. char* curToken = NULL;
  969. char* nextToken = NULL;
  970. char* newKey = NULL;
  971. char* newValue = NULL;
  972. char* newString = NULL;
  973. char* keyValue = NULL;
  974. ini = IniFile_New();
  975. if(!ini) {
  976. return FALSE;
  977. }
  978. if(IniFile_ReadFile(ini, lpFileName) < 0) {
  979. ret = FALSE;
  980. } else {
  981. if(lpAppName != NULL)
  982. {
  983. if (lpString == NULL)
  984. {
  985. printf("to delete the section...\n");
  986. ret = IniFile_RemoveSection(ini, lpAppName, &changed);
  987. }
  988. else
  989. {
  990. pSection = IniFile_GetSection(ini, lpAppName);
  991. if(!pSection)
  992. {
  993. pSection = IniFile_AddSection(ini, lpAppName);
  994. if(!pSection)
  995. {
  996. ret = FALSE;
  997. goto end;
  998. }
  999. changed = TRUE;
  1000. }
  1001. curToken = (char*)&lpString[0];
  1002. while (curToken != NULL && curToken[0] != '\0')
  1003. {
  1004. keyValue = _strdup(curToken);
  1005. if (!keyValue) {
  1006. ret = FALSE;
  1007. goto end;
  1008. }
  1009. newKey = strtok_s(keyValue, "=", &newValue);
  1010. newValue = strtok_s(NULL, "=", &newValue);
  1011. pKey = IniFile_GetKey(ini, pSection, newKey);
  1012. if (pKey == NULL) {
  1013. pKey = IniFile_AddKey(ini, pSection, newKey, newValue, NULL);
  1014. changed = TRUE;
  1015. } else if(_stricmp(pKey->value, newValue) != 0)
  1016. {
  1017. free(pKey->value);
  1018. pKey->value = _strdup(newValue);
  1019. if (!pKey->value)
  1020. {
  1021. free(keyValue);
  1022. ret = FALSE;
  1023. goto end;
  1024. }
  1025. changed = TRUE;
  1026. }
  1027. free(keyValue);
  1028. //curToken = strtok_s(NULL, "\0", &nextToken);
  1029. curToken = curToken + strlen(curToken) + 1;
  1030. }
  1031. }
  1032. }
  1033. }
  1034. if(ret == TRUE && changed) {
  1035. if(IniFile_WriteFile(ini, lpFileName) < 0)
  1036. {
  1037. ret = FALSE;
  1038. }
  1039. }
  1040. end:
  1041. if(newString != NULL)
  1042. {
  1043. free(newString);
  1044. }
  1045. IniFile_Free(ini);
  1046. return ret;
  1047. }
  1048. WINPR_API BOOL WritePrivateProfileSectionW(LPCWSTR lpAppName, LPCWSTR lpString,LPCWSTR lpFileName)
  1049. {
  1050. WLog_ERR(TAG, "%s operation not implemented", __FUNCTION__);
  1051. return FALSE;
  1052. }
  1053. #endif //_WIN32