IniFile.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. #include "IniFile.h"
  2. #include "FileService.h"
  3. //---------------------------------------------------------------------------------------------
  4. //IniFile
  5. //---------------------------------------------------------------------------------------------
  6. IniFile::IniFile(const char * _path, bool _isReadOnly, const char * _cppFileName, long _cppFileLine)
  7. {
  8. path = _path;
  9. parser.fileName = path;
  10. isChangeData = false;
  11. isReadOnly = _isReadOnly;
  12. lockRelease = false;
  13. #ifndef STOP_DEBUG
  14. cppFileName = _cppFileName;
  15. cppFileLine = _cppFileLine;
  16. #endif
  17. }
  18. IniFile::~IniFile()
  19. {
  20. }
  21. //Прочитать файл
  22. bool IniFile::Open(IFileService_DFOpenMode mode)
  23. {
  24. Assert(isReadOnly);
  25. IDataFile * file = FileService::object->OpenDataFile(path, mode, _FL_);
  26. if(file)
  27. {
  28. dword size = file->Size();
  29. void * ptr = parser.Reserved(size);
  30. if(file->Read(ptr, size) != size)
  31. {
  32. #ifndef STOP_DEBUG
  33. api->Error("FileService error: Can't read from ini file \"%s\" [read only mode] (file: %s, line: %i -> IniFile::Flush)", path.c_str(), cppFileName, cppFileLine);
  34. #endif
  35. return false;
  36. }
  37. file->Release();
  38. }else{
  39. #ifndef STOP_DEBUG
  40. api->Error("FileService error: Can't open ini file \"%s\" [read only mode] (file: %s, line: %i -> IniFile::Flush)", path.c_str(), cppFileName, cppFileLine);
  41. #endif
  42. return false;
  43. }
  44. parser.Parse();
  45. return true;
  46. }
  47. #ifndef _XBOX
  48. //Открыть файл
  49. bool IniFile::Open(IFileService_OpenMode mode)
  50. {
  51. Assert(!isReadOnly);
  52. IFile * file = FileService::object->OpenFile(path, mode, _FL_);
  53. if(file)
  54. {
  55. dword size = file->Size();
  56. void * ptr = parser.Reserved(size);
  57. if(file->Read(ptr, size) != size)
  58. {
  59. #ifndef STOP_DEBUG
  60. api->Error("FileService error: Can't read from ini file \"%s\" [editable mode] (file: %s, line: %i -> IniFile::Flush)", path.c_str(), cppFileName, cppFileLine);
  61. #endif
  62. return false;
  63. }
  64. file->Release();
  65. }else{
  66. #ifndef STOP_DEBUG
  67. api->Error("FileService error: Can't open ini file \"%s\" [editable mode] (file: %s, line: %i -> IniFile::Flush)", path.c_str(), cppFileName, cppFileLine);
  68. #endif
  69. return false;
  70. }
  71. if(mode == file_open_existing_for_read)
  72. {
  73. isReadOnly = true;
  74. }
  75. parser.Parse();
  76. return true;
  77. }
  78. #endif
  79. //Закрыть файл сообщив об ошибке
  80. void IniFile::ErrorRelease()
  81. {
  82. #ifndef STOP_DEBUG
  83. api->Error("FileService error: IIniFile file \"%s\" not release (file: %s, line %i)", path.c_str(), cppFileName, cppFileLine);
  84. #endif
  85. delete this;
  86. }
  87. //Блокировать возможность удалить файл
  88. void IniFile::LockRelease(bool isLock)
  89. {
  90. lockRelease = isLock;
  91. }
  92. //Закрыть файл
  93. void IniFile::Release()
  94. {
  95. if(lockRelease)
  96. {
  97. return;
  98. }
  99. if(!isReadOnly)
  100. {
  101. Flush();
  102. }
  103. SingleExClassThread(FileService::object)
  104. FileService::object->DeleteIniFile(this);
  105. delete this;
  106. }
  107. //Поулчить путь до файла
  108. const char * IniFile::GetPath() const
  109. {
  110. return path;
  111. }
  112. //Получить список секций
  113. void IniFile::GetSections(array<string> & sections)
  114. {
  115. sections.DelAll();
  116. parser.GetSections(sections);
  117. }
  118. //Добавить секцию
  119. void IniFile::AddSection(const char * section)
  120. {
  121. Assert(!isReadOnly);
  122. parser.AddSection(section);
  123. isChangeData = true;
  124. }
  125. //Удалить секцию с ключами
  126. void IniFile::DelSection(const char * section)
  127. {
  128. Assert(!isReadOnly);
  129. //Находим индекс секции
  130. long sectionIndex = parser.FindSection(section);
  131. if(sectionIndex >= 0)
  132. {
  133. parser.DelSection(sectionIndex);
  134. isChangeData = true;
  135. }
  136. }
  137. //Проверить наличие секции
  138. bool IniFile::IsSectionCreated(const char * section)
  139. {
  140. return (parser.FindSection(section) >= 0);
  141. }
  142. //Получить количество ключей
  143. dword IniFile::GetKeysCount(const char * section, const char * name)
  144. {
  145. //Подготовим имя ключа
  146. if(!name || !name[0]) return 0;
  147. long nameLen = strlen(name);
  148. //Находим индекс секции
  149. long sectionIndex = parser.FindSection(section);
  150. //Перебираем все одноимённые ключи в секции
  151. for(long keyIndex = -1, count = 0; true; count++)
  152. {
  153. keyIndex = parser.FindKey(sectionIndex, name, nameLen, keyIndex);
  154. if(keyIndex < 0) break;
  155. }
  156. return count;
  157. }
  158. //Проверить наличие ключа в секции
  159. bool IniFile::IsKeyCreated(const char * section, const char * name, long index)
  160. {
  161. if(!name || !name[0]) return false;
  162. //Находим индекс секции
  163. long sectionIndex = parser.FindSection(section);
  164. if(sectionIndex < 0)
  165. {
  166. return false;
  167. }
  168. long nameLen = strlen(name);
  169. return (parser.FindKey(sectionIndex, name, nameLen, index) >= 0);
  170. }
  171. //Удалить ключ
  172. void IniFile::DelKey(const char * section, const char * name, long index)
  173. {
  174. Assert(!isReadOnly);
  175. if(!name || !name[0]) return;
  176. //Находим индекс секции
  177. long sectionIndex = parser.FindSection(section);
  178. if(sectionIndex < 0)
  179. {
  180. return;
  181. }
  182. long nameLen = strlen(name);
  183. for(long keyIndex = -1; true; index--)
  184. {
  185. keyIndex = parser.FindKey(sectionIndex, name, nameLen, keyIndex);
  186. if(keyIndex < 0) break;
  187. if(index <= 0)
  188. {
  189. parser.DelKey(keyIndex);
  190. isChangeData = true;
  191. }
  192. }
  193. }
  194. //Установить значение ключа как строку
  195. void IniFile::SetString(const char * section, const char * name, const char * value, long index)
  196. {
  197. Assert(!isReadOnly);
  198. //Подготовим имя ключа
  199. if(!name || !name[0]) return;
  200. long nameLen = strlen(name);
  201. //Находим индекс секции}
  202. long sectionIndex = parser.AddSection(section);
  203. Assert(sectionIndex >= 0);
  204. //Ищим ключ
  205. for(long keyIndex = -1; true; index--)
  206. {
  207. keyIndex = parser.FindKey(sectionIndex, name, nameLen, keyIndex);
  208. if(keyIndex < 0)
  209. {
  210. isChangeData = true;
  211. if(index <= 0)
  212. {
  213. keyIndex = parser.AddKey(sectionIndex, name, value);
  214. return;
  215. }else{
  216. keyIndex = parser.AddKey(sectionIndex, name, "");
  217. }
  218. }
  219. if(index <= 0)
  220. {
  221. isChangeData = true;
  222. parser.SetKey(keyIndex, value);
  223. return;
  224. }
  225. }
  226. }
  227. //Получить значение ключа как строку
  228. const char * IniFile::GetString(const char * section, const char * name, const char * defValue, long index)
  229. {
  230. if(!name || !name[0]) return defValue;
  231. //Находим индекс секции
  232. long sectionIndex = parser.FindSection(section);
  233. if(sectionIndex < 0)
  234. {
  235. return defValue;
  236. }
  237. //Ищим ключ
  238. long nameLen = strlen(name);
  239. for(long keyIndex = -1; true; index--)
  240. {
  241. keyIndex = parser.FindKey(sectionIndex, name, nameLen, keyIndex);
  242. if(keyIndex < 0)
  243. {
  244. return defValue;
  245. }
  246. if(index <= 0)
  247. {
  248. return parser.GetKey(keyIndex);
  249. }
  250. }
  251. return defValue;
  252. }
  253. //Получить все значения ключа как строки
  254. void IniFile::GetStrings(const char * section, const char * name, array<string> & value)
  255. {
  256. value.DelAll();
  257. //Подготовим имя ключа
  258. if(!name || !name[0]) return;
  259. long nameLen = strlen(name);
  260. //Находим индекс секции
  261. long sectionIndex = parser.FindSection(section);
  262. //Перебираем все одноимённые ключи в секции
  263. long keyIndex = -1;
  264. while(true)
  265. {
  266. keyIndex = parser.FindKey(sectionIndex, name, nameLen, keyIndex);
  267. if(keyIndex < 0) return;
  268. value.Add(parser.GetKey(keyIndex));
  269. }
  270. }
  271. //Установить значение ключа как long
  272. void IniFile::SetLong(const char * section, const char * name, long value, long index)
  273. {
  274. char buf[128];
  275. crt_snprintf(buf, sizeof(buf), "%i", value);
  276. SetString(section, name, buf, index);
  277. }
  278. //Получить значение ключа как long
  279. long IniFile::GetLong(const char * section, const char * name, long defValue, long index)
  280. {
  281. const char * v = GetString(section, name, null, index);
  282. if(!v) return defValue;
  283. char * stop;
  284. return strtol(v, &stop, 10);
  285. }
  286. //Получить все значения ключа как long
  287. void IniFile::GetLongs(const char * section, const char * name, array<long> & value)
  288. {
  289. //Подготовим имя ключа
  290. if(!name || !name[0]) return;
  291. long nameLen = strlen(name);
  292. //Находим индекс секции
  293. long sectionIndex = parser.FindSection(section);
  294. //Перебираем все одноимённые ключи в секции
  295. long keyIndex = -1;
  296. while(true)
  297. {
  298. keyIndex = parser.FindKey(sectionIndex, name, nameLen, keyIndex);
  299. if(keyIndex < 0) return;
  300. const char * v = parser.GetKey(keyIndex);
  301. char * stop;
  302. long vl = strtol(v, &stop, 10);
  303. value.Add(vl);
  304. }
  305. }
  306. //Установить значение ключа как float
  307. void IniFile::SetFloat(const char * section, const char * name, float value, long index)
  308. {
  309. SetDouble(section, name, value, index);
  310. }
  311. //Получить значение ключа как float
  312. float IniFile::GetFloat(const char * section, const char * name, float defValue, long index)
  313. {
  314. return (float)GetDouble(section, name, defValue, index);
  315. }
  316. //Получить все значения ключа как float
  317. void IniFile::GetFloats(const char * section, const char * name, array<float> & value)
  318. {
  319. value.DelAll();
  320. //Подготовим имя ключа
  321. if(!name || !name[0]) return;
  322. long nameLen = strlen(name);
  323. //Находим индекс секции
  324. long sectionIndex = parser.FindSection(section);
  325. //Перебираем все одноимённые ключи в секции
  326. long keyIndex = -1;
  327. while(true)
  328. {
  329. keyIndex = parser.FindKey(sectionIndex, name, nameLen, keyIndex);
  330. if(keyIndex < 0) return;
  331. const char * v = parser.GetKey(keyIndex);
  332. char * stop;
  333. float vl = (float)strtod(v, &stop);
  334. value.Add(vl);
  335. }
  336. }
  337. //Установить значение ключа как double
  338. void IniFile::SetDouble(const char * section, const char * name, double value, long index)
  339. {
  340. char buf[128];
  341. crt_snprintf(buf, sizeof(buf), "%f", value);
  342. SetString(section, name, buf, index);
  343. }
  344. //Получить значение ключа как double
  345. double IniFile::GetDouble(const char * section, const char * name, double defValue, long index)
  346. {
  347. const char * v = GetString(section, name, null, index);
  348. if(!v) return defValue;
  349. char * stop;
  350. return strtod(v, &stop);
  351. }
  352. //Получить все значения ключа как double
  353. void IniFile::GetDoubles(const char * section, const char * name, array<double> & value)
  354. {
  355. value.DelAll();
  356. //Подготовим имя ключа
  357. if(!name || !name[0]) return;
  358. long nameLen = strlen(name);
  359. //Находим индекс секции
  360. long sectionIndex = parser.FindSection(section);
  361. //Перебираем все одноимённые ключи в секции
  362. long keyIndex = -1;
  363. while(true)
  364. {
  365. keyIndex = parser.FindKey(sectionIndex, name, nameLen, keyIndex);
  366. if(keyIndex < 0) return;
  367. const char * v = parser.GetKey(keyIndex);
  368. char * stop;
  369. double vl = strtod(v, &stop);
  370. value.Add(vl);
  371. }
  372. }
  373. //Сохранить изменения на диск немедленно
  374. void IniFile::Flush()
  375. {
  376. #ifndef _XBOX
  377. Assert(!isReadOnly);
  378. dword size = 0;
  379. const void * data = parser.GetBuffer(size);
  380. IFile * file = FileService::object->OpenFile(path, file_create_always, _FL_);
  381. if(file)
  382. {
  383. if(file->Write(data, size) != size)
  384. {
  385. #ifndef STOP_DEBUG
  386. api->Error("FileService error: Can't write to file \"%s\" (file: %s, line: %i -> IniFile::Flush)", path.c_str(), cppFileName, cppFileLine);
  387. #endif
  388. }
  389. file->Release();
  390. }else{
  391. #ifndef STOP_DEBUG
  392. api->Error("FileService error: Can't open to write ini file \"%s\" (file: %s, line: %i -> IniFile::Flush)", path.c_str(), cppFileName, cppFileLine);
  393. #endif
  394. }
  395. #endif
  396. }