flipper_format.c 19 KB

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