LiteINI.pas 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. {
  2. Copyright 2014 Stas'M Corp.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. }
  13. unit LiteINI;
  14. interface
  15. uses
  16. SysUtils;
  17. type
  18. SList = Array of String;
  19. INIValue = record
  20. Name: String;
  21. Value: String;
  22. end;
  23. INISection = record
  24. Name: String;
  25. Values: Array of INIValue;
  26. end;
  27. INIFile = Array of INISection;
  28. procedure SListClear(var List: SList);
  29. function SListAppend(var List: SList; S: String): Integer;
  30. function SListFind(List: SList; Value: String): Integer;
  31. function INIFindSection(INI: INIFile; Section: String): Integer;
  32. function INIFindValue(INI: INIFile; Section: Integer; Value: String): Integer;
  33. function INIAddSection(var INI: INIFile; Section: String): Integer;
  34. function INIAddValue(var INI: INIFile; Section: Integer; ValueName, Value: String): Integer;
  35. procedure INIUnload(var INI: INIFile);
  36. procedure INILoad(var INI: INIFile; FileName: String);
  37. function INISectionExists(INI: INIFile; Section: String): Boolean;
  38. function INIValueExists(INI: INIFile; Section: String; Value: String): Boolean;
  39. function INIReadSectionLowAPI(INI: INIFile; Section: Integer; var List: SList): Boolean;
  40. function INIReadSection(INI: INIFile; Section: String): SList;
  41. function INIReadStringLowAPI(INI: INIFile; Section, Value: Integer; var Str: String): Boolean;
  42. function INIReadString(INI: INIFile; Section, Value, Default: String): String;
  43. function INIReadInt(INI: INIFile; Section, Value: String; Default: Integer): Integer;
  44. function INIReadDWord(INI: INIFile; Section, Value: String; Default: Cardinal): Cardinal;
  45. function INIReadIntHex(INI: INIFile; Section, Value: String; Default: Integer): Integer;
  46. function INIReadDWordHex(INI: INIFile; Section, Value: String; Default: Cardinal): Cardinal;
  47. function INIReadBool(INI: INIFile; Section, Value: String; Default: Boolean): Boolean;
  48. function INIReadBytes(INI: INIFile; Section, Value: String): TBytes;
  49. function INIReadBytesDef(INI: INIFile; Section, Value: String; Default: TBytes): TBytes;
  50. implementation
  51. procedure SListClear(var List: SList);
  52. begin
  53. SetLength(List, 0);
  54. end;
  55. function SListAppend(var List: SList; S: String): Integer;
  56. begin
  57. SetLength(List, Length(List) + 1);
  58. List[Length(List) - 1] := S;
  59. Result := Length(List) - 1;
  60. end;
  61. function SListFind(List: SList; Value: String): Integer;
  62. var
  63. I: Integer;
  64. begin
  65. Result := -1;
  66. for I := 0 to Length(List) - 1 do
  67. if List[I] = Value then begin
  68. Result := I;
  69. Break;
  70. end;
  71. end;
  72. function INIFindSection(INI: INIFile; Section: String): Integer;
  73. var
  74. I: Integer;
  75. begin
  76. Result := -1;
  77. for I := 0 to Length(INI) - 1 do
  78. if INI[I].Name = Section then begin
  79. Result := I;
  80. Exit;
  81. end;
  82. end;
  83. function INIFindValue(INI: INIFile; Section: Integer; Value: String): Integer;
  84. var
  85. I: Integer;
  86. begin
  87. Result := -1;
  88. if (Section < 0) or (Section >= Length(INI)) then
  89. Exit;
  90. for I := 0 to Length(INI[Section].Values) - 1 do
  91. if INI[Section].Values[I].Name = Value then begin
  92. Result := I;
  93. Exit;
  94. end;
  95. end;
  96. function INIAddSection(var INI: INIFile; Section: String): Integer;
  97. begin
  98. Result := INIFindSection(INI, Section);
  99. if Result >= 0 then
  100. Exit;
  101. Result := Length(INI);
  102. SetLength(INI, Result + 1);
  103. INI[Result].Name := Section;
  104. SetLength(INI[Result].Values, 0);
  105. end;
  106. function INIAddValue(var INI: INIFile; Section: Integer; ValueName, Value: String): Integer;
  107. var
  108. I: Integer;
  109. begin
  110. Result := -1;
  111. if (Section < 0) or (Section >= Length(INI)) then
  112. Exit;
  113. I := INIFindValue(INI, Section, ValueName);
  114. if I = -1 then begin
  115. Result := Length(INI[Section].Values);
  116. SetLength(INI[Section].Values, Result + 1);
  117. INI[Section].Values[Result].Name := ValueName;
  118. INI[Section].Values[Result].Value := Value;
  119. end else begin
  120. INI[Section].Values[I].Value := Value;
  121. Result := I;
  122. end;
  123. end;
  124. procedure INIUnload(var INI: INIFile);
  125. begin
  126. SetLength(INI, 0);
  127. end;
  128. procedure INILoad(var INI: INIFile; FileName: String);
  129. var
  130. F: TextFile;
  131. S, ValueName, Value: String;
  132. INIList: SList;
  133. I, Sect: Integer;
  134. begin
  135. INIUnload(INI);
  136. if not FileExists(FileName) then
  137. Exit;
  138. AssignFile(F, FileName);
  139. Reset(F);
  140. // Read and filter lines
  141. while not EOF(F) do begin
  142. Readln(F, S);
  143. if (Pos(';', S) <> 1)
  144. and (Pos('#', S) <> 1)
  145. and (
  146. ((Pos('[', S) > 0) and (Pos(']', S) > 0)) or
  147. (Pos('=', S) > 0)
  148. )
  149. then
  150. SListAppend(INIList, S);
  151. end;
  152. CloseFile(F);
  153. // Parse 2 (parse format)
  154. Sect := -1;
  155. for I := 0 to Length(INIList) - 1 do begin
  156. S := Trim(INIList[I]);
  157. if Length(S) >= 2 then
  158. if (S[1] = '[') and (S[Length(S)] = ']') then begin
  159. S := Trim(Copy(S, 2, Length(S) - 2));
  160. Sect := INIAddSection(INI, S);
  161. Continue;
  162. end;
  163. S := INIList[I];
  164. if Pos('=', S) > 0 then begin
  165. ValueName := Trim(Copy(S, 1, Pos('=', S) - 1));
  166. Value := Copy(S, Pos('=', S) + 1, Length(S) - Pos('=', S));
  167. if Sect = -1 then
  168. Sect := INIAddSection(INI, '');
  169. INIAddValue(INI, Sect, ValueName, Value);
  170. end;
  171. end;
  172. end;
  173. function INISectionExists(INI: INIFile; Section: String): Boolean;
  174. begin
  175. Result := INIFindSection(INI, Section) > -1;
  176. end;
  177. function INIValueExists(INI: INIFile; Section: String; Value: String): Boolean;
  178. var
  179. Sect: Integer;
  180. begin
  181. Sect := INIFindSection(INI, Section);
  182. Result := INIFindValue(INI, Sect, Value) > -1;
  183. end;
  184. function INIReadSectionLowAPI(INI: INIFile; Section: Integer; var List: SList): Boolean;
  185. var
  186. I: Integer;
  187. begin
  188. Result := False;
  189. SetLength(List, 0);
  190. if (Section < 0) or (Section >= Length(INI)) then
  191. Exit;
  192. for I := 0 to Length(INI[Section].Values) - 1 do
  193. SListAppend(List, INI[Section].Values[I].Name);
  194. Result := True;
  195. end;
  196. function INIReadSection(INI: INIFile; Section: String): SList;
  197. var
  198. Sect: Integer;
  199. begin
  200. Sect := INIFindSection(INI, Section);
  201. INIReadSectionLowAPI(INI, Sect, Result);
  202. end;
  203. function INIReadStringLowAPI(INI: INIFile; Section, Value: Integer; var Str: String): Boolean;
  204. begin
  205. Result := False;
  206. if (Section < 0) or (Section >= Length(INI)) then
  207. Exit;
  208. if (Value < 0) or (Value >= Length(INI[Section].Values)) then
  209. Exit;
  210. Str := INI[Section].Values[Value].Value;
  211. Result := True;
  212. end;
  213. function INIReadString(INI: INIFile; Section, Value, Default: String): String;
  214. var
  215. Sect, Val: Integer;
  216. begin
  217. Sect := INIFindSection(INI, Section);
  218. Val := INIFindValue(INI, Sect, Value);
  219. if not INIReadStringLowAPI(INI, Sect, Val, Result) then
  220. Result := Default;
  221. end;
  222. function INIReadInt(INI: INIFile; Section, Value: String; Default: Integer): Integer;
  223. var
  224. S: String;
  225. E: Integer;
  226. begin
  227. S := INIReadString(INI, Section, Value, '');
  228. Val(S, Result, E);
  229. if E <> 0 then
  230. Result := Default;
  231. end;
  232. function INIReadDWord(INI: INIFile; Section, Value: String; Default: Cardinal): Cardinal;
  233. var
  234. S: String;
  235. E: Integer;
  236. begin
  237. S := INIReadString(INI, Section, Value, '');
  238. Val(S, Result, E);
  239. if E <> 0 then
  240. Result := Default;
  241. end;
  242. function INIReadIntHex(INI: INIFile; Section, Value: String; Default: Integer): Integer;
  243. var
  244. S: String;
  245. E: Integer;
  246. begin
  247. S := INIReadString(INI, Section, Value, '');
  248. Val('$'+S, Result, E);
  249. if E <> 0 then
  250. Result := Default;
  251. end;
  252. function INIReadDWordHex(INI: INIFile; Section, Value: String; Default: Cardinal): Cardinal;
  253. var
  254. S: String;
  255. E: Integer;
  256. begin
  257. S := INIReadString(INI, Section, Value, '');
  258. Val('$'+S, Result, E);
  259. if E <> 0 then
  260. Result := Default;
  261. end;
  262. function INIReadBool(INI: INIFile; Section, Value: String; Default: Boolean): Boolean;
  263. var
  264. S: String;
  265. I: Cardinal;
  266. E: Integer;
  267. begin
  268. S := INIReadString(INI, Section, Value, '');
  269. Val(S, I, E);
  270. if E <> 0 then
  271. Result := Default
  272. else
  273. Result := I > 0;
  274. end;
  275. function StringToBytes(S: String; var B: TBytes): Boolean;
  276. var
  277. I: Integer;
  278. begin
  279. Result := False;
  280. if Odd(Length(S)) then
  281. Exit;
  282. SetLength(B, Length(S) div 2);
  283. for I := 0 to Length(B) - 1 do begin
  284. B[I] := 0;
  285. case S[(I*2)+2] of
  286. '0': ;
  287. '1': B[I] := B[I] or $1;
  288. '2': B[I] := B[I] or $2;
  289. '3': B[I] := B[I] or $3;
  290. '4': B[I] := B[I] or $4;
  291. '5': B[I] := B[I] or $5;
  292. '6': B[I] := B[I] or $6;
  293. '7': B[I] := B[I] or $7;
  294. '8': B[I] := B[I] or $8;
  295. '9': B[I] := B[I] or $9;
  296. 'A','a': B[I] := B[I] or $A;
  297. 'B','b': B[I] := B[I] or $B;
  298. 'C','c': B[I] := B[I] or $C;
  299. 'D','d': B[I] := B[I] or $D;
  300. 'E','e': B[I] := B[I] or $E;
  301. 'F','f': B[I] := B[I] or $F;
  302. else Exit;
  303. end;
  304. case S[(I*2)+1] of
  305. '0': ;
  306. '1': B[I] := B[I] or $10;
  307. '2': B[I] := B[I] or $20;
  308. '3': B[I] := B[I] or $30;
  309. '4': B[I] := B[I] or $40;
  310. '5': B[I] := B[I] or $50;
  311. '6': B[I] := B[I] or $60;
  312. '7': B[I] := B[I] or $70;
  313. '8': B[I] := B[I] or $80;
  314. '9': B[I] := B[I] or $90;
  315. 'A','a': B[I] := B[I] or $A0;
  316. 'B','b': B[I] := B[I] or $B0;
  317. 'C','c': B[I] := B[I] or $C0;
  318. 'D','d': B[I] := B[I] or $D0;
  319. 'E','e': B[I] := B[I] or $E0;
  320. 'F','f': B[I] := B[I] or $F0;
  321. else Exit;
  322. end;
  323. end;
  324. Result := True;
  325. end;
  326. function INIReadBytes(INI: INIFile; Section, Value: String): TBytes;
  327. var
  328. S: String;
  329. begin
  330. S := INIReadString(INI, Section, Value, '');
  331. if not StringToBytes(S, Result) then
  332. SetLength(Result, 0);
  333. end;
  334. function INIReadBytesDef(INI: INIFile; Section, Value: String; Default: TBytes): TBytes;
  335. var
  336. S: String;
  337. begin
  338. S := INIReadString(INI, Section, Value, '');
  339. if not StringToBytes(S, Result) then
  340. Result := Default;
  341. end;
  342. end.