flipper_format.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644
  1. #include <core/check.h>
  2. #include <toolbox/stream/stream.h>
  3. #include <toolbox/stream/string_stream.h>
  4. #include <toolbox/stream/file_stream.h>
  5. #include <toolbox/stream/buffered_file_stream.h>
  6. #include "flipper_format.h"
  7. #include "flipper_format_i.h"
  8. #include "flipper_format_stream.h"
  9. #include "flipper_format_stream_i.h"
  10. /********************************** Private **********************************/
  11. struct FlipperFormat {
  12. Stream* stream;
  13. bool strict_mode;
  14. };
  15. static const char* const flipper_format_filetype_key = "Filetype";
  16. static const char* const flipper_format_version_key = "Version";
  17. Stream* flipper_format_get_raw_stream(FlipperFormat* flipper_format) {
  18. return flipper_format->stream;
  19. }
  20. /********************************** Public **********************************/
  21. FlipperFormat* flipper_format_string_alloc() {
  22. FlipperFormat* flipper_format = malloc(sizeof(FlipperFormat));
  23. flipper_format->stream = string_stream_alloc();
  24. flipper_format->strict_mode = false;
  25. return flipper_format;
  26. }
  27. FlipperFormat* flipper_format_file_alloc(Storage* storage) {
  28. FlipperFormat* flipper_format = malloc(sizeof(FlipperFormat));
  29. flipper_format->stream = file_stream_alloc(storage);
  30. flipper_format->strict_mode = false;
  31. return flipper_format;
  32. }
  33. FlipperFormat* flipper_format_buffered_file_alloc(Storage* storage) {
  34. FlipperFormat* flipper_format = malloc(sizeof(FlipperFormat));
  35. flipper_format->stream = buffered_file_stream_alloc(storage);
  36. flipper_format->strict_mode = false;
  37. return flipper_format;
  38. }
  39. bool flipper_format_file_open_existing(FlipperFormat* flipper_format, const char* path) {
  40. furi_assert(flipper_format);
  41. return file_stream_open(flipper_format->stream, path, FSAM_READ_WRITE, FSOM_OPEN_EXISTING);
  42. }
  43. bool flipper_format_buffered_file_open_existing(FlipperFormat* flipper_format, const char* path) {
  44. furi_assert(flipper_format);
  45. return buffered_file_stream_open(
  46. flipper_format->stream, path, FSAM_READ_WRITE, FSOM_OPEN_EXISTING);
  47. }
  48. bool flipper_format_file_open_append(FlipperFormat* flipper_format, const char* path) {
  49. furi_assert(flipper_format);
  50. bool result =
  51. file_stream_open(flipper_format->stream, path, FSAM_READ_WRITE, FSOM_OPEN_APPEND);
  52. // Add EOL if it is not there
  53. if(stream_size(flipper_format->stream) >= 1) {
  54. do {
  55. char last_char;
  56. result = false;
  57. if(!stream_seek(flipper_format->stream, -1, StreamOffsetFromEnd)) break;
  58. uint16_t bytes_were_read =
  59. stream_read(flipper_format->stream, (uint8_t*)&last_char, 1);
  60. if(bytes_were_read != 1) break;
  61. if(last_char != flipper_format_eoln) {
  62. if(!flipper_format_stream_write_eol(flipper_format->stream)) break;
  63. }
  64. result = true;
  65. } while(false);
  66. } else {
  67. stream_seek(flipper_format->stream, 0, StreamOffsetFromEnd);
  68. }
  69. return result;
  70. }
  71. bool flipper_format_file_open_always(FlipperFormat* flipper_format, const char* path) {
  72. furi_assert(flipper_format);
  73. return file_stream_open(flipper_format->stream, path, FSAM_READ_WRITE, FSOM_CREATE_ALWAYS);
  74. }
  75. bool flipper_format_buffered_file_open_always(FlipperFormat* flipper_format, const char* path) {
  76. furi_assert(flipper_format);
  77. return buffered_file_stream_open(
  78. flipper_format->stream, path, FSAM_READ_WRITE, FSOM_CREATE_ALWAYS);
  79. }
  80. bool flipper_format_file_open_new(FlipperFormat* flipper_format, const char* path) {
  81. furi_assert(flipper_format);
  82. return file_stream_open(flipper_format->stream, path, FSAM_READ_WRITE, FSOM_CREATE_NEW);
  83. }
  84. bool flipper_format_file_close(FlipperFormat* flipper_format) {
  85. furi_assert(flipper_format);
  86. return file_stream_close(flipper_format->stream);
  87. }
  88. bool flipper_format_buffered_file_close(FlipperFormat* flipper_format) {
  89. furi_assert(flipper_format);
  90. return buffered_file_stream_close(flipper_format->stream);
  91. }
  92. void flipper_format_free(FlipperFormat* flipper_format) {
  93. furi_assert(flipper_format);
  94. stream_free(flipper_format->stream);
  95. free(flipper_format);
  96. }
  97. void flipper_format_set_strict_mode(FlipperFormat* flipper_format, bool strict_mode) {
  98. flipper_format->strict_mode = strict_mode;
  99. }
  100. bool flipper_format_rewind(FlipperFormat* flipper_format) {
  101. furi_assert(flipper_format);
  102. return stream_rewind(flipper_format->stream);
  103. }
  104. bool flipper_format_seek_to_end(FlipperFormat* flipper_format) {
  105. furi_assert(flipper_format);
  106. return stream_seek(flipper_format->stream, 0, StreamOffsetFromEnd);
  107. }
  108. bool flipper_format_key_exist(FlipperFormat* flipper_format, const char* key) {
  109. size_t pos = stream_tell(flipper_format->stream);
  110. stream_seek(flipper_format->stream, 0, StreamOffsetFromStart);
  111. bool result = flipper_format_stream_seek_to_key(flipper_format->stream, key, false);
  112. stream_seek(flipper_format->stream, pos, StreamOffsetFromStart);
  113. return result;
  114. }
  115. bool flipper_format_read_header(
  116. FlipperFormat* flipper_format,
  117. FuriString* filetype,
  118. uint32_t* version) {
  119. furi_assert(flipper_format);
  120. return flipper_format_read_string(flipper_format, flipper_format_filetype_key, filetype) &&
  121. flipper_format_read_uint32(flipper_format, flipper_format_version_key, version, 1);
  122. }
  123. bool flipper_format_write_header(
  124. FlipperFormat* flipper_format,
  125. FuriString* filetype,
  126. const uint32_t version) {
  127. furi_assert(flipper_format);
  128. return flipper_format_write_header_cstr(
  129. flipper_format, furi_string_get_cstr(filetype), version);
  130. }
  131. bool flipper_format_write_header_cstr(
  132. FlipperFormat* flipper_format,
  133. const char* filetype,
  134. const uint32_t version) {
  135. furi_assert(flipper_format);
  136. return flipper_format_write_string_cstr(
  137. flipper_format, flipper_format_filetype_key, filetype) &&
  138. flipper_format_write_uint32(flipper_format, flipper_format_version_key, &version, 1);
  139. }
  140. bool flipper_format_get_value_count(
  141. FlipperFormat* flipper_format,
  142. const char* key,
  143. uint32_t* count) {
  144. furi_assert(flipper_format);
  145. return flipper_format_stream_get_value_count(
  146. flipper_format->stream, key, count, flipper_format->strict_mode);
  147. }
  148. bool flipper_format_read_string(FlipperFormat* flipper_format, const char* key, FuriString* data) {
  149. furi_assert(flipper_format);
  150. return flipper_format_stream_read_value_line(
  151. flipper_format->stream, key, FlipperStreamValueStr, data, 1, flipper_format->strict_mode);
  152. }
  153. bool flipper_format_write_string(FlipperFormat* flipper_format, const char* key, FuriString* data) {
  154. furi_assert(flipper_format);
  155. FlipperStreamWriteData write_data = {
  156. .key = key,
  157. .type = FlipperStreamValueStr,
  158. .data = furi_string_get_cstr(data),
  159. .data_size = 1,
  160. };
  161. bool result = flipper_format_stream_write_value_line(flipper_format->stream, &write_data);
  162. return result;
  163. }
  164. bool flipper_format_write_string_cstr(
  165. FlipperFormat* flipper_format,
  166. const char* key,
  167. const char* data) {
  168. furi_assert(flipper_format);
  169. FlipperStreamWriteData write_data = {
  170. .key = key,
  171. .type = FlipperStreamValueStr,
  172. .data = data,
  173. .data_size = 1,
  174. };
  175. bool result = flipper_format_stream_write_value_line(flipper_format->stream, &write_data);
  176. return result;
  177. }
  178. bool flipper_format_read_hex_uint64(
  179. FlipperFormat* flipper_format,
  180. const char* key,
  181. uint64_t* data,
  182. const uint16_t data_size) {
  183. furi_assert(flipper_format);
  184. return flipper_format_stream_read_value_line(
  185. flipper_format->stream,
  186. key,
  187. FlipperStreamValueHexUint64,
  188. data,
  189. data_size,
  190. flipper_format->strict_mode);
  191. }
  192. bool flipper_format_write_hex_uint64(
  193. FlipperFormat* flipper_format,
  194. const char* key,
  195. const uint64_t* data,
  196. const uint16_t data_size) {
  197. furi_assert(flipper_format);
  198. FlipperStreamWriteData write_data = {
  199. .key = key,
  200. .type = FlipperStreamValueHexUint64,
  201. .data = data,
  202. .data_size = data_size,
  203. };
  204. bool result = flipper_format_stream_write_value_line(flipper_format->stream, &write_data);
  205. return result;
  206. }
  207. bool flipper_format_read_uint32(
  208. FlipperFormat* flipper_format,
  209. const char* key,
  210. uint32_t* data,
  211. const uint16_t data_size) {
  212. furi_assert(flipper_format);
  213. return flipper_format_stream_read_value_line(
  214. flipper_format->stream,
  215. key,
  216. FlipperStreamValueUint32,
  217. data,
  218. data_size,
  219. flipper_format->strict_mode);
  220. }
  221. bool flipper_format_write_uint32(
  222. FlipperFormat* flipper_format,
  223. const char* key,
  224. const uint32_t* data,
  225. const uint16_t data_size) {
  226. furi_assert(flipper_format);
  227. FlipperStreamWriteData write_data = {
  228. .key = key,
  229. .type = FlipperStreamValueUint32,
  230. .data = data,
  231. .data_size = data_size,
  232. };
  233. bool result = flipper_format_stream_write_value_line(flipper_format->stream, &write_data);
  234. return result;
  235. }
  236. bool flipper_format_read_int32(
  237. FlipperFormat* flipper_format,
  238. const char* key,
  239. int32_t* data,
  240. const uint16_t data_size) {
  241. return flipper_format_stream_read_value_line(
  242. flipper_format->stream,
  243. key,
  244. FlipperStreamValueInt32,
  245. data,
  246. data_size,
  247. flipper_format->strict_mode);
  248. }
  249. bool flipper_format_write_int32(
  250. FlipperFormat* flipper_format,
  251. const char* key,
  252. const int32_t* data,
  253. const uint16_t data_size) {
  254. furi_assert(flipper_format);
  255. FlipperStreamWriteData write_data = {
  256. .key = key,
  257. .type = FlipperStreamValueInt32,
  258. .data = data,
  259. .data_size = data_size,
  260. };
  261. bool result = flipper_format_stream_write_value_line(flipper_format->stream, &write_data);
  262. return result;
  263. }
  264. bool flipper_format_read_bool(
  265. FlipperFormat* flipper_format,
  266. const char* key,
  267. bool* data,
  268. const uint16_t data_size) {
  269. return flipper_format_stream_read_value_line(
  270. flipper_format->stream,
  271. key,
  272. FlipperStreamValueBool,
  273. data,
  274. data_size,
  275. flipper_format->strict_mode);
  276. }
  277. bool flipper_format_write_bool(
  278. FlipperFormat* flipper_format,
  279. const char* key,
  280. const bool* data,
  281. const uint16_t data_size) {
  282. furi_assert(flipper_format);
  283. FlipperStreamWriteData write_data = {
  284. .key = key,
  285. .type = FlipperStreamValueBool,
  286. .data = data,
  287. .data_size = data_size,
  288. };
  289. bool result = flipper_format_stream_write_value_line(flipper_format->stream, &write_data);
  290. return result;
  291. }
  292. bool flipper_format_read_float(
  293. FlipperFormat* flipper_format,
  294. const char* key,
  295. float* data,
  296. const uint16_t data_size) {
  297. return flipper_format_stream_read_value_line(
  298. flipper_format->stream,
  299. key,
  300. FlipperStreamValueFloat,
  301. data,
  302. data_size,
  303. flipper_format->strict_mode);
  304. }
  305. bool flipper_format_write_float(
  306. FlipperFormat* flipper_format,
  307. const char* key,
  308. const float* data,
  309. const uint16_t data_size) {
  310. furi_assert(flipper_format);
  311. FlipperStreamWriteData write_data = {
  312. .key = key,
  313. .type = FlipperStreamValueFloat,
  314. .data = data,
  315. .data_size = data_size,
  316. };
  317. bool result = flipper_format_stream_write_value_line(flipper_format->stream, &write_data);
  318. return result;
  319. }
  320. bool flipper_format_read_hex(
  321. FlipperFormat* flipper_format,
  322. const char* key,
  323. uint8_t* data,
  324. const uint16_t data_size) {
  325. return flipper_format_stream_read_value_line(
  326. flipper_format->stream,
  327. key,
  328. FlipperStreamValueHex,
  329. data,
  330. data_size,
  331. flipper_format->strict_mode);
  332. }
  333. bool flipper_format_write_hex(
  334. FlipperFormat* flipper_format,
  335. const char* key,
  336. const uint8_t* data,
  337. const uint16_t data_size) {
  338. furi_assert(flipper_format);
  339. FlipperStreamWriteData write_data = {
  340. .key = key,
  341. .type = FlipperStreamValueHex,
  342. .data = data,
  343. .data_size = data_size,
  344. };
  345. bool result = flipper_format_stream_write_value_line(flipper_format->stream, &write_data);
  346. return result;
  347. }
  348. bool flipper_format_write_comment(FlipperFormat* flipper_format, FuriString* data) {
  349. furi_assert(flipper_format);
  350. return flipper_format_write_comment_cstr(flipper_format, furi_string_get_cstr(data));
  351. }
  352. bool flipper_format_write_comment_cstr(FlipperFormat* flipper_format, const char* data) {
  353. furi_assert(flipper_format);
  354. return flipper_format_stream_write_comment_cstr(flipper_format->stream, data);
  355. }
  356. bool flipper_format_delete_key(FlipperFormat* flipper_format, const char* key) {
  357. furi_assert(flipper_format);
  358. FlipperStreamWriteData write_data = {
  359. .key = key,
  360. .type = FlipperStreamValueIgnore,
  361. .data = NULL,
  362. .data_size = 0,
  363. };
  364. bool result = flipper_format_stream_delete_key_and_write(
  365. flipper_format->stream, &write_data, flipper_format->strict_mode);
  366. return result;
  367. }
  368. bool flipper_format_update_string(FlipperFormat* flipper_format, const char* key, FuriString* data) {
  369. furi_assert(flipper_format);
  370. FlipperStreamWriteData write_data = {
  371. .key = key,
  372. .type = FlipperStreamValueStr,
  373. .data = furi_string_get_cstr(data),
  374. .data_size = 1,
  375. };
  376. bool result = flipper_format_stream_delete_key_and_write(
  377. flipper_format->stream, &write_data, flipper_format->strict_mode);
  378. return result;
  379. }
  380. bool flipper_format_update_string_cstr(
  381. FlipperFormat* flipper_format,
  382. const char* key,
  383. const char* data) {
  384. furi_assert(flipper_format);
  385. FlipperStreamWriteData write_data = {
  386. .key = key,
  387. .type = FlipperStreamValueStr,
  388. .data = data,
  389. .data_size = 1,
  390. };
  391. bool result = flipper_format_stream_delete_key_and_write(
  392. flipper_format->stream, &write_data, flipper_format->strict_mode);
  393. return result;
  394. }
  395. bool flipper_format_update_uint32(
  396. FlipperFormat* flipper_format,
  397. const char* key,
  398. const uint32_t* data,
  399. const uint16_t data_size) {
  400. furi_assert(flipper_format);
  401. FlipperStreamWriteData write_data = {
  402. .key = key,
  403. .type = FlipperStreamValueUint32,
  404. .data = data,
  405. .data_size = data_size,
  406. };
  407. bool result = flipper_format_stream_delete_key_and_write(
  408. flipper_format->stream, &write_data, flipper_format->strict_mode);
  409. return result;
  410. }
  411. bool flipper_format_update_int32(
  412. FlipperFormat* flipper_format,
  413. const char* key,
  414. const int32_t* data,
  415. const uint16_t data_size) {
  416. FlipperStreamWriteData write_data = {
  417. .key = key,
  418. .type = FlipperStreamValueInt32,
  419. .data = data,
  420. .data_size = data_size,
  421. };
  422. bool result = flipper_format_stream_delete_key_and_write(
  423. flipper_format->stream, &write_data, flipper_format->strict_mode);
  424. return result;
  425. }
  426. bool flipper_format_update_bool(
  427. FlipperFormat* flipper_format,
  428. const char* key,
  429. const bool* data,
  430. const uint16_t data_size) {
  431. FlipperStreamWriteData write_data = {
  432. .key = key,
  433. .type = FlipperStreamValueBool,
  434. .data = data,
  435. .data_size = data_size,
  436. };
  437. bool result = flipper_format_stream_delete_key_and_write(
  438. flipper_format->stream, &write_data, flipper_format->strict_mode);
  439. return result;
  440. }
  441. bool flipper_format_update_float(
  442. FlipperFormat* flipper_format,
  443. const char* key,
  444. const float* data,
  445. const uint16_t data_size) {
  446. FlipperStreamWriteData write_data = {
  447. .key = key,
  448. .type = FlipperStreamValueFloat,
  449. .data = data,
  450. .data_size = data_size,
  451. };
  452. bool result = flipper_format_stream_delete_key_and_write(
  453. flipper_format->stream, &write_data, flipper_format->strict_mode);
  454. return result;
  455. }
  456. bool flipper_format_update_hex(
  457. FlipperFormat* flipper_format,
  458. const char* key,
  459. const uint8_t* data,
  460. const uint16_t data_size) {
  461. FlipperStreamWriteData write_data = {
  462. .key = key,
  463. .type = FlipperStreamValueHex,
  464. .data = data,
  465. .data_size = data_size,
  466. };
  467. bool result = flipper_format_stream_delete_key_and_write(
  468. flipper_format->stream, &write_data, flipper_format->strict_mode);
  469. return result;
  470. }
  471. bool flipper_format_insert_or_update_string(
  472. FlipperFormat* flipper_format,
  473. const char* key,
  474. FuriString* data) {
  475. bool result = false;
  476. if(!flipper_format_key_exist(flipper_format, key)) {
  477. flipper_format_seek_to_end(flipper_format);
  478. result = flipper_format_write_string(flipper_format, key, data);
  479. } else {
  480. result = flipper_format_update_string(flipper_format, key, data);
  481. }
  482. return result;
  483. }
  484. bool flipper_format_insert_or_update_string_cstr(
  485. FlipperFormat* flipper_format,
  486. const char* key,
  487. const char* data) {
  488. bool result = false;
  489. if(!flipper_format_key_exist(flipper_format, key)) {
  490. flipper_format_seek_to_end(flipper_format);
  491. result = flipper_format_write_string_cstr(flipper_format, key, data);
  492. } else {
  493. result = flipper_format_update_string_cstr(flipper_format, key, data);
  494. }
  495. return result;
  496. }
  497. bool flipper_format_insert_or_update_uint32(
  498. FlipperFormat* flipper_format,
  499. const char* key,
  500. const uint32_t* data,
  501. const uint16_t data_size) {
  502. bool result = false;
  503. if(!flipper_format_key_exist(flipper_format, key)) {
  504. flipper_format_seek_to_end(flipper_format);
  505. result = flipper_format_write_uint32(flipper_format, key, data, data_size);
  506. } else {
  507. result = flipper_format_update_uint32(flipper_format, key, data, data_size);
  508. }
  509. return result;
  510. }
  511. bool flipper_format_insert_or_update_int32(
  512. FlipperFormat* flipper_format,
  513. const char* key,
  514. const int32_t* data,
  515. const uint16_t data_size) {
  516. bool result = false;
  517. if(!flipper_format_key_exist(flipper_format, key)) {
  518. flipper_format_seek_to_end(flipper_format);
  519. result = flipper_format_write_int32(flipper_format, key, data, data_size);
  520. } else {
  521. result = flipper_format_update_int32(flipper_format, key, data, data_size);
  522. }
  523. return result;
  524. }
  525. bool flipper_format_insert_or_update_bool(
  526. FlipperFormat* flipper_format,
  527. const char* key,
  528. const bool* data,
  529. const uint16_t data_size) {
  530. bool result = false;
  531. if(!flipper_format_key_exist(flipper_format, key)) {
  532. flipper_format_seek_to_end(flipper_format);
  533. result = flipper_format_write_bool(flipper_format, key, data, data_size);
  534. } else {
  535. result = flipper_format_update_bool(flipper_format, key, data, data_size);
  536. }
  537. return result;
  538. }
  539. bool flipper_format_insert_or_update_float(
  540. FlipperFormat* flipper_format,
  541. const char* key,
  542. const float* data,
  543. const uint16_t data_size) {
  544. bool result = false;
  545. if(!flipper_format_key_exist(flipper_format, key)) {
  546. flipper_format_seek_to_end(flipper_format);
  547. result = flipper_format_write_float(flipper_format, key, data, data_size);
  548. } else {
  549. result = flipper_format_update_float(flipper_format, key, data, data_size);
  550. }
  551. return result;
  552. }
  553. bool flipper_format_insert_or_update_hex(
  554. FlipperFormat* flipper_format,
  555. const char* key,
  556. const uint8_t* data,
  557. const uint16_t data_size) {
  558. bool result = false;
  559. if(!flipper_format_key_exist(flipper_format, key)) {
  560. flipper_format_seek_to_end(flipper_format);
  561. result = flipper_format_write_hex(flipper_format, key, data, data_size);
  562. } else {
  563. result = flipper_format_update_hex(flipper_format, key, data, data_size);
  564. }
  565. return result;
  566. }