Bläddra i källkod

[FL-1919] NFC rework with Flipper File Format (#756)

* nfc: allocate nfc device on heap
* nfc: rework save with flipper file format
* nfc: rework nfc device load with flipper file
* nfc: save AID length and data
* nfc: remove file worker usage
* nfc: format sources
* nfc: rework with flipper file format addons
* assets: update EMV resources with flipper file format
* nfc: rework EMV resources parsing with new file format
* assets: fix EMV AID file format
* nfc: fix nfc_device usage

Co-authored-by: あく <alleteam@gmail.com>
gornekich 4 år sedan
förälder
incheckning
90d450368c
36 ändrade filer med 993 tillägg och 1055 borttagningar
  1. 56 25
      applications/nfc/helpers/nfc_emv_parser.c
  2. 17 3
      applications/nfc/helpers/nfc_emv_parser.h
  3. 8 2
      applications/nfc/nfc.c
  4. 226 334
      applications/nfc/nfc_device.c
  5. 8 0
      applications/nfc/nfc_device.h
  6. 0 16
      applications/nfc/nfc_device_i.h
  7. 1 1
      applications/nfc/nfc_i.h
  8. 2 0
      applications/nfc/nfc_worker.c
  9. 4 4
      applications/nfc/scenes/nfc_scene_card_menu.c
  10. 3 3
      applications/nfc/scenes/nfc_scene_delete.c
  11. 33 15
      applications/nfc/scenes/nfc_scene_device_info.c
  12. 1 1
      applications/nfc/scenes/nfc_scene_emulate_apdu_sequence.c
  13. 4 4
      applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c
  14. 4 4
      applications/nfc/scenes/nfc_scene_emulate_uid.c
  15. 1 1
      applications/nfc/scenes/nfc_scene_file_select.c
  16. 2 2
      applications/nfc/scenes/nfc_scene_mifare_ul_menu.c
  17. 1 1
      applications/nfc/scenes/nfc_scene_read_card.c
  18. 2 2
      applications/nfc/scenes/nfc_scene_read_card_success.c
  19. 1 1
      applications/nfc/scenes/nfc_scene_read_emv_app.c
  20. 4 3
      applications/nfc/scenes/nfc_scene_read_emv_app_success.c
  21. 2 2
      applications/nfc/scenes/nfc_scene_read_emv_data.c
  22. 8 7
      applications/nfc/scenes/nfc_scene_read_emv_data_success.c
  23. 1 1
      applications/nfc/scenes/nfc_scene_read_mifare_ul.c
  24. 2 2
      applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c
  25. 7 7
      applications/nfc/scenes/nfc_scene_save_name.c
  26. 4 4
      applications/nfc/scenes/nfc_scene_saved_menu.c
  27. 1 1
      applications/nfc/scenes/nfc_scene_set_atqa.c
  28. 1 1
      applications/nfc/scenes/nfc_scene_set_sak.c
  29. 5 5
      applications/nfc/scenes/nfc_scene_set_type.c
  30. 1 1
      applications/nfc/scenes/nfc_scene_set_uid.c
  31. 1 1
      applications/nfc/scenes/nfc_scene_start.c
  32. 6 34
      applications/nfc/views/bank_card.c
  33. 2 2
      applications/nfc/views/bank_card.h
  34. 151 148
      assets/resources/nfc/emv/aid.nfc
  35. 252 249
      assets/resources/nfc/emv/country_code.nfc
  36. 171 168
      assets/resources/nfc/emv/currency_code.nfc

+ 56 - 25
applications/nfc/helpers/nfc_emv_parser.c

@@ -1,49 +1,80 @@
 #include "nfc_emv_parser.h"
+#include <lib/flipper_file/flipper_file.h>
 
-#include <file-worker.h>
+static const char* nfc_resources_header = "Flipper EMV resources";
+static const uint32_t nfc_resources_file_version = 1;
 
-static bool
-    nfc_emv_parser_get_value(const char* file_path, string_t key, char delimiter, string_t value) {
-    bool found = false;
-    FileWorker* file_worker = file_worker_alloc(true);
+static bool nfc_emv_parser_search_data(
+    Storage* storage,
+    const char* file_name,
+    string_t key,
+    string_t data) {
+    bool parsed = false;
+    FlipperFile* file = flipper_file_alloc(storage);
+    string_t temp_str;
+    string_init(temp_str);
 
-    if(file_worker_open(file_worker, file_path, FSAM_READ, FSOM_OPEN_EXISTING)) {
-        if(file_worker_get_value_from_key(file_worker, key, delimiter, value)) {
-            found = true;
-        }
-    }
+    do {
+        // Open file
+        if(!flipper_file_open_existing(file, file_name)) break;
+        // Read file header and version
+        uint32_t version = 0;
+        if(!flipper_file_read_header(file, temp_str, &version)) break;
+        if(string_cmp_str(temp_str, nfc_resources_header) ||
+           (version != nfc_resources_file_version))
+            break;
+        if(!flipper_file_read_string(file, string_get_cstr(key), data)) break;
+        parsed = true;
+    } while(false);
 
-    file_worker_close(file_worker);
-    file_worker_free(file_worker);
-    return found;
+    string_clear(temp_str);
+    flipper_file_free(file);
+    return parsed;
 }
 
-bool nfc_emv_parser_get_aid_name(uint8_t* aid, uint8_t aid_len, string_t aid_name) {
-    bool result = false;
+bool nfc_emv_parser_get_aid_name(
+    Storage* storage,
+    uint8_t* aid,
+    uint8_t aid_len,
+    string_t aid_name) {
+    furi_assert(storage);
+    bool parsed = false;
     string_t key;
     string_init(key);
     for(uint8_t i = 0; i < aid_len; i++) {
         string_cat_printf(key, "%02X", aid[i]);
     }
-    result = nfc_emv_parser_get_value("/ext/nfc/emv/aid.nfc", key, ' ', aid_name);
+    if(nfc_emv_parser_search_data(storage, "/ext/nfc/emv/aid.nfc", key, aid_name)) {
+        parsed = true;
+    }
     string_clear(key);
-    return result;
+    return parsed;
 }
 
-bool nfc_emv_parser_get_country_name(uint16_t country_code, string_t country_name) {
-    bool result = false;
+bool nfc_emv_parser_get_country_name(
+    Storage* storage,
+    uint16_t country_code,
+    string_t country_name) {
+    bool parsed = false;
     string_t key;
     string_init_printf(key, "%04X", country_code);
-    result = nfc_emv_parser_get_value("/ext/nfc/emv/country_code.nfc", key, ' ', country_name);
+    if(nfc_emv_parser_search_data(storage, "/ext/nfc/emv/country_code.nfc", key, country_name)) {
+        parsed = true;
+    }
     string_clear(key);
-    return result;
+    return parsed;
 }
 
-bool nfc_emv_parser_get_currency_name(uint16_t currency_code, string_t currency_name) {
-    bool result = false;
+bool nfc_emv_parser_get_currency_name(
+    Storage* storage,
+    uint16_t currency_code,
+    string_t currency_name) {
+    bool parsed = false;
     string_t key;
     string_init_printf(key, "%04X", currency_code);
-    result = nfc_emv_parser_get_value("/ext/nfc/emv/currency_code.nfc", key, ' ', currency_name);
+    if(nfc_emv_parser_search_data(storage, "/ext/nfc/emv/currency_code.nfc", key, currency_name)) {
+        parsed = true;
+    }
     string_clear(key);
-    return result;
+    return parsed;
 }

+ 17 - 3
applications/nfc/helpers/nfc_emv_parser.h

@@ -3,25 +3,39 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include <m-string.h>
+#include <storage/storage.h>
 
 /** Get EMV application name by number
+ * @param storage Storage instance
  * @param aid - AID number array
  * @param aid_len - AID length
  * @param aid_name - string to keep AID name
  * @return - true if AID found, false otherwies
  */
-bool nfc_emv_parser_get_aid_name(uint8_t* aid, uint8_t aid_len, string_t aid_name);
+bool nfc_emv_parser_get_aid_name(
+    Storage* storage,
+    uint8_t* aid,
+    uint8_t aid_len,
+    string_t aid_name);
 
 /** Get country name by country code
+ * @param storage Storage instance
  * @param country_code - ISO 3166 country code
  * @param country_name - string to keep country name
  * @return - true if country found, false otherwies
  */
-bool nfc_emv_parser_get_country_name(uint16_t country_code, string_t country_name);
+bool nfc_emv_parser_get_country_name(
+    Storage* storage,
+    uint16_t country_code,
+    string_t country_name);
 
 /** Get currency name by currency code
+ * @param storage Storage instance
  * @param currency_code - ISO 3166 currency code
  * @param currency_name - string to keep currency name
  * @return - true if currency found, false otherwies
  */
-bool nfc_emv_parser_get_currency_name(uint16_t currency_code, string_t currency_name);
+bool nfc_emv_parser_get_currency_name(
+    Storage* storage,
+    uint16_t currency_code,
+    string_t currency_name);

+ 8 - 2
applications/nfc/nfc.c

@@ -31,6 +31,9 @@ Nfc* nfc_alloc() {
     view_dispatcher_set_navigation_event_callback(nfc->view_dispatcher, nfc_back_event_callback);
     view_dispatcher_set_tick_event_callback(nfc->view_dispatcher, nfc_tick_event_callback, 100);
 
+    // Nfc device
+    nfc->dev = nfc_device_alloc();
+
     // Open GUI record
     nfc->gui = furi_record_open("gui");
     view_dispatcher_attach_to_gui(nfc->view_dispatcher, nfc->gui, ViewDispatcherTypeFullscreen);
@@ -82,6 +85,9 @@ Nfc* nfc_alloc() {
 void nfc_free(Nfc* nfc) {
     furi_assert(nfc);
 
+    // Nfc device
+    nfc_device_free(nfc->dev);
+
     // Submenu
     view_dispatcher_remove_view(nfc->view_dispatcher, NfcViewMenu);
     submenu_free(nfc->submenu);
@@ -154,8 +160,8 @@ int32_t nfc_app(void* p) {
     char* args = p;
 
     // Check argument and run corresponding scene
-    if((*args != '\0') && nfc_device_load(&nfc->dev, p)) {
-        if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) {
+    if((*args != '\0') && nfc_device_load(nfc->dev, p)) {
+        if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
         } else {
             scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);

+ 226 - 334
applications/nfc/nfc_device.c

@@ -1,45 +1,38 @@
-#include "nfc_device_i.h"
+#include "nfc_device.h"
 
-#include <file-worker.h>
 #include <lib/toolbox/path.h>
-#include <lib/toolbox/hex.h>
-
-#define NFC_DEVICE_MAX_DATA_LEN 14
+#include <lib/flipper_file/flipper_file.h>
 
 static const char* nfc_app_folder = "/any/nfc";
 static const char* nfc_app_extension = ".nfc";
 static const char* nfc_app_shadow_extension = ".shd";
+static const char* nfc_file_header = "Flipper NFC device";
+static const uint32_t nfc_file_version = 2;
+
+NfcDevice* nfc_device_alloc() {
+    NfcDevice* nfc_dev = furi_alloc(sizeof(NfcDevice));
+    nfc_dev->storage = furi_record_open("storage");
+    nfc_dev->dialogs = furi_record_open("dialogs");
+    return nfc_dev;
+}
 
-static bool nfc_device_read_hex(string_t str, uint8_t* buff, uint16_t len, uint8_t delim_len) {
-    string_strim(str);
-    uint8_t nibble_high = 0;
-    uint8_t nibble_low = 0;
-    bool parsed = true;
-
-    for(uint16_t i = 0; i < len; i++) {
-        if(hex_char_to_hex_nibble(string_get_char(str, 0), &nibble_high) &&
-           hex_char_to_hex_nibble(string_get_char(str, 1), &nibble_low)) {
-            buff[i] = (nibble_high << 4) | nibble_low;
-            string_right(str, delim_len + 2);
-        } else {
-            parsed = false;
-            break;
-        }
-    }
-    return parsed;
+void nfc_device_free(NfcDevice* nfc_dev) {
+    furi_assert(nfc_dev);
+    furi_record_close("storage");
+    furi_record_close("dialogs");
+    free(nfc_dev);
 }
 
-uint16_t nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string) {
+void nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string) {
     if(dev->format == NfcDeviceSaveFormatUid) {
-        string_set_str(format_string, "UID\n");
+        string_set_str(format_string, "UID");
     } else if(dev->format == NfcDeviceSaveFormatBankCard) {
-        string_set_str(format_string, "Bank card\n");
+        string_set_str(format_string, "Bank card");
     } else if(dev->format == NfcDeviceSaveFormatMifareUl) {
-        string_set_str(format_string, "Mifare Ultralight\n");
+        string_set_str(format_string, "Mifare Ultralight");
     } else {
-        string_set_str(format_string, "Unknown\n");
+        string_set_str(format_string, "Unknown");
     }
-    return string_size(format_string);
 }
 
 bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) {
@@ -59,228 +52,166 @@ bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string) {
     return false;
 }
 
-uint16_t nfc_device_prepare_uid_string(NfcDevice* dev, string_t uid_string) {
-    NfcDeviceCommonData* uid_data = &dev->dev_data.nfc_data;
-    string_printf(uid_string, "UID len: %02X UID: ", dev->dev_data.nfc_data.uid_len);
-    for(uint8_t i = 0; i < uid_data->uid_len; i++) {
-        string_cat_printf(uid_string, "%02X ", uid_data->uid[i]);
-    }
-    string_cat_printf(
-        uid_string,
-        "ATQA: %02X %02X SAK: %02X\n",
-        uid_data->atqa[0],
-        uid_data->atqa[1],
-        uid_data->sak);
-    return string_size(uid_string);
-}
-
-bool nfc_device_parse_uid_string(NfcDevice* dev, string_t uid_string) {
-    NfcDeviceCommonData* uid_data = &dev->dev_data.nfc_data;
-    bool parsed = false;
+static bool nfc_device_save_mifare_ul_data(FlipperFile* file, NfcDevice* dev) {
+    bool saved = false;
+    MifareUlData* data = &dev->dev_data.mf_ul_data;
+    string_t temp_str;
+    string_init(temp_str);
 
+    // Save Mifare Ultralight specific data
     do {
-        // strlen("UID len: ") = 9
-        string_right(uid_string, 9);
-        if(!nfc_device_read_hex(uid_string, &uid_data->uid_len, 1, 1)) {
+        if(!flipper_file_write_comment_cstr(file, "Mifare Ultralight specific data")) break;
+        if(!flipper_file_write_hex(file, "Signature", data->signature, sizeof(data->signature)))
             break;
-        }
-        // strlen("UID: ") = 5
-        string_right(uid_string, 5);
-        if(!nfc_device_read_hex(uid_string, uid_data->uid, uid_data->uid_len, 1)) {
-            break;
-        }
-        // strlen("ATQA: ") = 6
-        string_right(uid_string, 6);
-        if(!nfc_device_read_hex(uid_string, uid_data->atqa, 2, 1)) {
+        if(!flipper_file_write_hex(
+               file, "Mifare version", (uint8_t*)&data->version, sizeof(data->version)))
             break;
+        // Write conters and tearing flags data
+        bool counters_saved = true;
+        for(uint8_t i = 0; i < 3; i++) {
+            string_printf(temp_str, "Counter %d", i);
+            if(!flipper_file_write_uint32(file, string_get_cstr(temp_str), &data->counter[i], 1)) {
+                counters_saved = false;
+                break;
+            }
+            string_printf(temp_str, "Tearing %d", i);
+            if(!flipper_file_write_hex(file, string_get_cstr(temp_str), &data->tearing[i], 1)) {
+                counters_saved = false;
+                break;
+            }
         }
-        // strlen("SAK: ") = 5
-        string_right(uid_string, 5);
-        if(!nfc_device_read_hex(uid_string, &uid_data->sak, 1, 1)) {
-            break;
+        if(!counters_saved) break;
+        // Write pages data
+        uint32_t pages_total = data->data_size / 4;
+        if(!flipper_file_write_uint32(file, "Pages total", &pages_total, 1)) break;
+        bool pages_saved = true;
+        for(uint16_t i = 0; i < data->data_size; i += 4) {
+            string_printf(temp_str, "Page %d", i / 4);
+            if(!flipper_file_write_hex(file, string_get_cstr(temp_str), &data->data[i], 4)) {
+                pages_saved = false;
+                break;
+            }
         }
-        parsed = true;
-    } while(0);
-
-    return parsed;
-}
+        if(!pages_saved) break;
+        saved = true;
+    } while(false);
 
-uint16_t nfc_device_prepare_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string) {
-    MifareUlData* data = &dev->dev_data.mf_ul_data;
-    string_printf(mifare_ul_string, "Signature:");
-    for(uint8_t i = 0; i < sizeof(data->signature); i++) {
-        string_cat_printf(mifare_ul_string, " %02X", data->signature[i]);
-    }
-    string_cat_printf(mifare_ul_string, "\nVersion:");
-    uint8_t* version = (uint8_t*)&data->version;
-    for(uint8_t i = 0; i < sizeof(data->version); i++) {
-        string_cat_printf(mifare_ul_string, " %02X", version[i]);
-    }
-    for(uint8_t i = 0; i < 3; i++) {
-        string_cat_printf(
-            mifare_ul_string,
-            "\nCounter %d: %lu Tearing flag %d: %02X",
-            i,
-            data->counter[i],
-            i,
-            data->tearing[i]);
-    }
-    string_cat_printf(mifare_ul_string, "\nData size: %d\n", data->data_size);
-    for(uint16_t i = 0; i < data->data_size; i += 4) {
-        string_cat_printf(
-            mifare_ul_string,
-            "%02X %02X %02X %02X\n",
-            data->data[i],
-            data->data[i + 1],
-            data->data[i + 2],
-            data->data[i + 3]);
-    }
-    return string_size(mifare_ul_string);
+    string_clear(temp_str);
+    return saved;
 }
 
-bool nfc_device_parse_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string) {
-    MifareUlData* data = &dev->dev_data.mf_ul_data;
-    uint16_t tearing_tmp = 0;
-    uint16_t cnt_num = 0;
-    size_t ws = 0;
-    int res = 0;
+bool nfc_device_load_mifare_ul_data(FlipperFile* file, NfcDevice* dev) {
     bool parsed = false;
+    MifareUlData* data = &dev->dev_data.mf_ul_data;
+    string_t temp_str;
+    string_init(temp_str);
 
     do {
-        // strlen("Signature: ") = 11
-        string_right(mifare_ul_string, 11);
-        if(!nfc_device_read_hex(mifare_ul_string, data->signature, sizeof(data->signature), 1)) {
+        // Read signature
+        if(!flipper_file_read_hex(file, "Signature", data->signature, sizeof(data->signature)))
             break;
-        }
-        // strlen("Version: ") = 9
-        string_right(mifare_ul_string, 9);
-        if(!nfc_device_read_hex(
-               mifare_ul_string, (uint8_t*)&data->version, sizeof(data->version), 1)) {
+        // Read Mifare version
+        if(!flipper_file_read_hex(
+               file, "Mifare version", (uint8_t*)&data->version, sizeof(data->version)))
             break;
-        }
-        string_strim(mifare_ul_string);
         // Read counters and tearing flags
+        bool counters_parsed = true;
         for(uint8_t i = 0; i < 3; i++) {
-            res = sscanf(
-                string_get_cstr(mifare_ul_string),
-                "Counter %hX: %lu Tearing flag %hX: %02hX",
-                &cnt_num,
-                &data->counter[i],
-                &cnt_num,
-                &tearing_tmp);
-            if(res != 4) {
+            string_printf(temp_str, "Counter %d", i);
+            if(!flipper_file_read_uint32(file, string_get_cstr(temp_str), &data->counter[i], 1)) {
+                counters_parsed = false;
+                break;
+            }
+            string_printf(temp_str, "Tearing %d", i);
+            if(!flipper_file_read_hex(file, string_get_cstr(temp_str), &data->tearing[i], 1)) {
+                counters_parsed = false;
                 break;
             }
-            data->tearing[i] = tearing_tmp;
-            ws = string_search_char(mifare_ul_string, '\n');
-            string_right(mifare_ul_string, ws + 1);
-        }
-        // Read data size
-        res = sscanf(string_get_cstr(mifare_ul_string), "Data size: %hu", &data->data_size);
-        if(res != 1) {
-            break;
         }
-        ws = string_search_char(mifare_ul_string, '\n');
-        string_right(mifare_ul_string, ws + 1);
-        // Read data
-        for(uint16_t i = 0; i < data->data_size; i += 4) {
-            if(!nfc_device_read_hex(mifare_ul_string, &data->data[i], 4, 1)) {
+        if(!counters_parsed) break;
+        // Read pages
+        uint32_t pages = 0;
+        if(!flipper_file_read_uint32(file, "Pages total", &pages, 1)) break;
+        data->data_size = pages * 4;
+        bool pages_parsed = true;
+        for(uint16_t i = 0; i < pages; i++) {
+            string_printf(temp_str, "Page %d", i);
+            if(!flipper_file_read_hex(file, string_get_cstr(temp_str), &data->data[i * 4], 4)) {
+                pages_parsed = false;
                 break;
             }
         }
+        if(!pages_parsed) break;
         parsed = true;
-    } while(0);
+    } while(false);
 
+    string_clear(temp_str);
     return parsed;
 }
 
-uint16_t nfc_device_prepare_bank_card_string(NfcDevice* dev, string_t bank_card_string) {
+static bool nfc_device_save_bank_card_data(FlipperFile* file, NfcDevice* dev) {
+    bool saved = false;
     NfcEmvData* data = &dev->dev_data.emv_data;
-    string_printf(bank_card_string, "AID len: %d, AID:", data->aid_len);
-    for(uint8_t i = 0; i < data->aid_len; i++) {
-        string_cat_printf(bank_card_string, " %02X", data->aid[i]);
-    }
-    string_cat_printf(
-        bank_card_string, "\nName: %s\nNumber len: %d\nNumber:", data->name, data->number_len);
-    for(uint8_t i = 0; i < data->number_len; i++) {
-        string_cat_printf(bank_card_string, " %02X", data->number[i]);
-    }
-    if(data->exp_mon) {
-        string_cat_printf(
-            bank_card_string, "\nExp date: %02X/%02X", data->exp_mon, data->exp_year);
-    }
-    if(data->country_code) {
-        string_cat_printf(bank_card_string, "\nCountry code: %04X", data->country_code);
-    }
-    if(data->currency_code) {
-        string_cat_printf(bank_card_string, "\nCurrency code: %04X", data->currency_code);
-    }
-    return string_size(bank_card_string);
+    uint32_t data_temp = 0;
+
+    do {
+        // Write Bank card specific data
+        if(!flipper_file_write_comment_cstr(file, "Bank card specific data")) break;
+        if(!flipper_file_write_hex(file, "AID", data->aid, data->aid_len)) break;
+        if(!flipper_file_write_string_cstr(file, "Name", data->name)) break;
+        if(!flipper_file_write_hex(file, "Number", data->number, data->number_len)) break;
+        if(data->exp_mon) {
+            uint8_t exp_data[2] = {data->exp_mon, data->exp_year};
+            if(!flipper_file_write_hex(file, "Exp data", exp_data, sizeof(exp_data))) break;
+        }
+        if(data->country_code) {
+            data_temp = data->country_code;
+            if(!flipper_file_write_uint32(file, "Country code", &data_temp, 1)) break;
+        }
+        if(data->currency_code) {
+            data_temp = data->currency_code;
+            if(!flipper_file_write_uint32(file, "Currency code", &data_temp, 1)) break;
+        }
+        saved = true;
+    } while(false);
+
+    return saved;
 }
 
-bool nfc_device_parse_bank_card_string(NfcDevice* dev, string_t bank_card_string) {
-    NfcEmvData* data = &dev->dev_data.emv_data;
+bool nfc_device_load_bank_card_data(FlipperFile* file, NfcDevice* dev) {
     bool parsed = false;
-    int res = 0;
-    uint8_t code[2] = {};
+    NfcEmvData* data = &dev->dev_data.emv_data;
     memset(data, 0, sizeof(NfcEmvData));
+    uint32_t data_cnt = 0;
+    string_t temp_str;
+    string_init(temp_str);
 
     do {
-        res = sscanf(string_get_cstr(bank_card_string), "AID len: %hu", &data->aid_len);
-        if(res != 1) {
-            break;
-        }
-        // strlen("AID len: ") = 9
-        string_right(bank_card_string, 9);
-        size_t ws = string_search_char(bank_card_string, ':');
-        string_right(bank_card_string, ws + 1);
-        if(!nfc_device_read_hex(bank_card_string, data->aid, data->aid_len, 1)) {
-            break;
-        }
-        res = sscanf(string_get_cstr(bank_card_string), "Name: %s\n", data->name);
-        if(res != 1) {
-            break;
-        }
-        ws = string_search_char(bank_card_string, '\n');
-        string_right(bank_card_string, ws + 1);
-        res = sscanf(string_get_cstr(bank_card_string), "Number len: %hhu", &data->number_len);
-        if(res != 1) {
-            break;
-        }
-        ws = string_search_char(bank_card_string, '\n');
-        string_right(bank_card_string, ws + 1);
-        // strlen("Number: ") = 8
-        string_right(bank_card_string, 8);
-        if(!nfc_device_read_hex(bank_card_string, data->number, data->number_len, 1)) {
-            break;
-        }
+        // Load essential data
+        if(!flipper_file_get_value_count(file, "AID", &data_cnt)) break;
+        data->aid_len = data_cnt;
+        if(!flipper_file_read_hex(file, "AID", data->aid, data->aid_len)) break;
+        if(!flipper_file_read_string(file, "Name", temp_str)) break;
+        strlcpy(data->name, string_get_cstr(temp_str), sizeof(data->name));
+        if(!flipper_file_get_value_count(file, "Number", &data_cnt)) break;
+        data->number_len = data_cnt;
+        if(!flipper_file_read_hex(file, "Number", data->number, data->number_len)) break;
         parsed = true;
-        // Check expiration date presence
-        ws = string_search_str(bank_card_string, "Exp date: ");
-        if(ws != STRING_FAILURE) {
-            // strlen("Exp date: ") = 10
-            string_right(bank_card_string, 10);
-            nfc_device_read_hex(bank_card_string, &data->exp_mon, 1, 1);
-            nfc_device_read_hex(bank_card_string, &data->exp_year, 1, 1);
+        // Load optional data
+        uint8_t exp_data[2] = {};
+        if(flipper_file_read_hex(file, "Exp data", exp_data, 2)) {
+            data->exp_mon = exp_data[0];
+            data->exp_year = exp_data[1];
         }
-        // Check country code presence
-        ws = string_search_str(bank_card_string, "Country code: ");
-        if(ws != STRING_FAILURE) {
-            // strlen("Country code: ") = 14
-            string_right(bank_card_string, 14);
-            nfc_device_read_hex(bank_card_string, code, 2, 0);
-            data->country_code = code[0] << 8 | code[1];
+        if(flipper_file_read_uint32(file, "Country code", &data_cnt, 1)) {
+            data->country_code = data_cnt;
         }
-        // Check currency code presence
-        ws = string_search_str(bank_card_string, "Currency code: ");
-        if(ws != STRING_FAILURE) {
-            // strlen("Currency code: ") = 15
-            string_right(bank_card_string, 15);
-            nfc_device_read_hex(bank_card_string, code, 2, 0);
-            data->currency_code = code[0] << 8 | code[1];
+        if(flipper_file_read_uint32(file, "Currency code", &data_cnt, 1)) {
+            data->currency_code = data_cnt;
         }
-    } while(0);
+    } while(false);
 
+    string_clear(temp_str);
     return parsed;
 }
 
@@ -297,58 +228,49 @@ static bool nfc_device_save_file(
     const char* extension) {
     furi_assert(dev);
 
-    FileWorker* file_worker = file_worker_alloc(false);
-    string_t dev_file_name;
-    string_init(dev_file_name);
+    bool saved = false;
+    FlipperFile* file = flipper_file_alloc(dev->storage);
+    NfcDeviceCommonData* data = &dev->dev_data.nfc_data;
     string_t temp_str;
     string_init(temp_str);
-    uint16_t string_len = 0;
 
     do {
         // Create nfc directory if necessary
-        if(!file_worker_mkdir(file_worker, nfc_app_folder)) {
-            break;
-        };
+        if(!storage_simply_mkdir(dev->storage, nfc_app_folder)) break;
         // First remove nfc device file if it was saved
-        string_printf(dev_file_name, "%s/%s%s", folder, dev_name, extension);
-        if(!file_worker_remove(file_worker, string_get_cstr(dev_file_name))) {
-            break;
-        };
+        string_printf(temp_str, "%s/%s%s", folder, dev_name, extension);
         // Open file
-        if(!file_worker_open(
-               file_worker, string_get_cstr(dev_file_name), FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
-            break;
-        }
-        // Prepare and write format name on 1st line
-        string_len = nfc_device_prepare_format_string(dev, temp_str);
-        if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) {
+        if(!flipper_file_open_always(file, string_get_cstr(temp_str))) break;
+        // Write header
+        if(!flipper_file_write_header_cstr(file, nfc_file_header, nfc_file_version)) break;
+        // Write nfc device type
+        if(!flipper_file_write_comment_cstr(
+               file, "Nfc device type can be UID, Mifare Ultralight, Bank card"))
             break;
-        }
-        // Prepare and write UID data on 2nd line
-        string_len = nfc_device_prepare_uid_string(dev, temp_str);
-        if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) {
+        nfc_device_prepare_format_string(dev, temp_str);
+        if(!flipper_file_write_string(file, "Device type", temp_str)) break;
+        // Write UID, ATQA, SAK
+        if(!flipper_file_write_comment_cstr(file, "UID, ATQA and SAK are common for all formats"))
             break;
-        }
+        if(!flipper_file_write_hex(file, "UID", data->uid, data->uid_len)) break;
+        if(!flipper_file_write_hex(file, "ATQA", data->atqa, 2)) break;
+        if(!flipper_file_write_hex(file, "SAK", &data->sak, 1)) break;
         // Save more data if necessary
         if(dev->format == NfcDeviceSaveFormatMifareUl) {
-            string_len = nfc_device_prepare_mifare_ul_string(dev, temp_str);
-            if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) {
-                break;
-            }
+            if(!nfc_device_save_mifare_ul_data(file, dev)) break;
         } else if(dev->format == NfcDeviceSaveFormatBankCard) {
-            string_len = nfc_device_prepare_bank_card_string(dev, temp_str);
-            if(!file_worker_write(file_worker, string_get_cstr(temp_str), string_len)) {
-                break;
-            }
+            if(!nfc_device_save_bank_card_data(file, dev)) break;
         }
+        saved = true;
     } while(0);
 
+    if(!saved) {
+        dialog_message_show_storage_error(dev->dialogs, "Can not save\nkey file");
+    }
     string_clear(temp_str);
-    string_clear(dev_file_name);
-    file_worker_close(file_worker);
-    file_worker_free(file_worker);
-
-    return true;
+    flipper_file_close(file);
+    flipper_file_free(file);
+    return saved;
 }
 
 bool nfc_device_save(NfcDevice* dev, const char* dev_name) {
@@ -360,73 +282,64 @@ bool nfc_device_save_shadow(NfcDevice* dev, const char* dev_name) {
     return nfc_device_save_file(dev, dev_name, nfc_app_folder, nfc_app_shadow_extension);
 }
 
-static bool nfc_device_load_data(FileWorker* file_worker, string_t path, NfcDevice* dev) {
-    string_t temp_string;
-    string_init(temp_string);
+static bool nfc_device_load_data(NfcDevice* dev, string_t path) {
     bool parsed = false;
+    FlipperFile* file = flipper_file_alloc(dev->storage);
+    NfcDeviceCommonData* data = &dev->dev_data.nfc_data;
+    uint32_t data_cnt = 0;
+    string_t temp_str;
+    string_init(temp_str);
+    bool depricated_version = false;
 
     do {
         // Check existance of shadow file
         size_t ext_start = string_search_str(path, nfc_app_extension);
-        string_set_n(temp_string, path, 0, ext_start);
-        string_cat_printf(temp_string, "%s", nfc_app_shadow_extension);
-        if(!file_worker_is_file_exist(
-               file_worker, string_get_cstr(temp_string), &dev->shadow_file_exist)) {
-            break;
-        }
+        string_set_n(temp_str, path, 0, ext_start);
+        string_cat_printf(temp_str, "%s", nfc_app_shadow_extension);
+        dev->shadow_file_exist =
+            storage_common_stat(dev->storage, string_get_cstr(temp_str), NULL) == FSE_OK;
         // Open shadow file if it exists. If not - open original
         if(dev->shadow_file_exist) {
-            if(!file_worker_open(
-                   file_worker, string_get_cstr(temp_string), FSAM_READ, FSOM_OPEN_EXISTING)) {
-                break;
-            }
+            if(!flipper_file_open_existing(file, string_get_cstr(temp_str))) break;
         } else {
-            if(!file_worker_open(
-                   file_worker, string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
-                break;
-            }
+            if(!flipper_file_open_existing(file, string_get_cstr(path))) break;
         }
-
-        // Read and parse format from 1st line
-        if(!file_worker_read_until(file_worker, temp_string, '\n')) {
-            break;
-        }
-        if(!nfc_device_parse_format_string(dev, temp_string)) {
-            break;
-        }
-        // Read and parse UID data from 2nd line
-        if(!file_worker_read_until(file_worker, temp_string, '\n')) {
-            break;
-        }
-        if(!nfc_device_parse_uid_string(dev, temp_string)) {
+        // Read and verify file header
+        uint32_t version = 0;
+        if(!flipper_file_read_header(file, temp_str, &version)) break;
+        if(string_cmp_str(temp_str, nfc_file_header) || (version != nfc_file_version)) {
+            depricated_version = true;
             break;
         }
+        // Read Nfc device type
+        if(!flipper_file_read_string(file, "Device type", temp_str)) break;
+        if(!nfc_device_parse_format_string(dev, temp_str)) break;
+        // Read and parse UID, ATQA and SAK
+        if(!flipper_file_get_value_count(file, "UID", &data_cnt)) break;
+        data->uid_len = data_cnt;
+        if(!flipper_file_read_hex(file, "UID", data->uid, data->uid_len)) break;
+        if(!flipper_file_read_hex(file, "ATQA", data->atqa, 2)) break;
+        if(!flipper_file_read_hex(file, "SAK", &data->sak, 1)) break;
         // Parse other data
         if(dev->format == NfcDeviceSaveFormatMifareUl) {
-            // Read until EOF
-            if(!file_worker_read_until(file_worker, temp_string, 0x05)) {
-                break;
-            }
-            if(!nfc_device_parse_mifare_ul_string(dev, temp_string)) {
-                break;
-            }
+            if(!nfc_device_load_mifare_ul_data(file, dev)) break;
         } else if(dev->format == NfcDeviceSaveFormatBankCard) {
-            // Read until EOF
-            if(!file_worker_read_until(file_worker, temp_string, 0x05)) {
-                break;
-            }
-            if(!nfc_device_parse_bank_card_string(dev, temp_string)) {
-                break;
-            }
+            if(!nfc_device_load_bank_card_data(file, dev)) break;
         }
         parsed = true;
-    } while(0);
+    } while(false);
 
     if(!parsed) {
-        file_worker_show_error(file_worker, "Can not parse\nfile");
+        if(depricated_version) {
+            dialog_message_show_storage_error(dev->dialogs, "File format depricated");
+        } else {
+            dialog_message_show_storage_error(dev->dialogs, "Can not parse\nfile");
+        }
     }
 
-    string_clear(temp_string);
+    string_clear(temp_str);
+    flipper_file_close(file);
+    flipper_file_free(file);
     return parsed;
 }
 
@@ -434,19 +347,16 @@ bool nfc_device_load(NfcDevice* dev, const char* file_path) {
     furi_assert(dev);
     furi_assert(file_path);
 
-    FileWorker* file_worker = file_worker_alloc(false);
     // Load device data
     string_t path;
     string_init_set_str(path, file_path);
-    bool dev_load = nfc_device_load_data(file_worker, path, dev);
+    bool dev_load = nfc_device_load_data(dev, path);
     if(dev_load) {
         // Set device name
         path_extract_filename_no_ext(file_path, path);
         nfc_device_set_name(dev, string_get_cstr(path));
     }
     string_clear(path);
-    file_worker_close(file_worker);
-    file_worker_free(file_worker);
 
     return dev_load;
 }
@@ -454,10 +364,9 @@ bool nfc_device_load(NfcDevice* dev, const char* file_path) {
 bool nfc_file_select(NfcDevice* dev) {
     furi_assert(dev);
 
-    FileWorker* file_worker = file_worker_alloc(false);
     // Input events and views are managed by file_select
-    bool res = file_worker_file_select(
-        file_worker,
+    bool res = dialog_file_select_show(
+        dev->dialogs,
         nfc_app_folder,
         nfc_app_extension,
         dev->file_name,
@@ -465,18 +374,14 @@ bool nfc_file_select(NfcDevice* dev) {
         dev->dev_name);
     if(res) {
         string_t dev_str;
-
         // Get key file path
         string_init_printf(dev_str, "%s/%s%s", nfc_app_folder, dev->file_name, nfc_app_extension);
-
-        res = nfc_device_load_data(file_worker, dev_str, dev);
+        res = nfc_device_load_data(dev, dev_str);
         if(res) {
             nfc_device_set_name(dev, dev->file_name);
         }
         string_clear(dev_str);
     }
-    file_worker_close(file_worker);
-    file_worker_free(file_worker);
 
     return res;
 }
@@ -491,61 +396,48 @@ void nfc_device_clear(NfcDevice* dev) {
 bool nfc_device_delete(NfcDevice* dev) {
     furi_assert(dev);
 
-    bool result = true;
-    FileWorker* file_worker = file_worker_alloc(false);
+    bool deleted = false;
     string_t file_path;
+    string_init(file_path);
 
     do {
         // Delete original file
         string_init_printf(file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension);
-        if(!file_worker_remove(file_worker, string_get_cstr(file_path))) {
-            result = false;
-            break;
-        }
+        if(!storage_simply_remove(dev->storage, string_get_cstr(file_path))) break;
         // Delete shadow file if it exists
         if(dev->shadow_file_exist) {
-            string_clean(file_path);
             string_printf(
                 file_path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension);
-            if(!file_worker_remove(file_worker, string_get_cstr(file_path))) {
-                result = false;
-                break;
-            }
+            if(!storage_simply_remove(dev->storage, string_get_cstr(file_path))) break;
         }
+        deleted = true;
     } while(0);
 
+    if(!deleted) {
+        dialog_message_show_storage_error(dev->dialogs, "Can not remove file");
+    }
+
     string_clear(file_path);
-    file_worker_close(file_worker);
-    file_worker_free(file_worker);
-    return result;
+    return deleted;
 }
 
 bool nfc_device_restore(NfcDevice* dev) {
     furi_assert(dev);
     furi_assert(dev->shadow_file_exist);
 
-    bool result = true;
-    FileWorker* file_worker = file_worker_alloc(false);
+    bool restored = false;
     string_t path;
 
     do {
         string_init_printf(
             path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_shadow_extension);
-        if(!file_worker_remove(file_worker, string_get_cstr(path))) {
-            result = false;
-            break;
-        }
+        if(!storage_simply_remove(dev->storage, string_get_cstr(path))) break;
         dev->shadow_file_exist = false;
-        string_clean(path);
         string_printf(path, "%s/%s%s", nfc_app_folder, dev->dev_name, nfc_app_extension);
-        if(!nfc_device_load_data(file_worker, path, dev)) {
-            result = false;
-            break;
-        }
+        if(!nfc_device_load_data(dev, path)) break;
+        restored = true;
     } while(0);
 
     string_clear(path);
-    file_worker_close(file_worker);
-    file_worker_free(file_worker);
-    return result;
+    return restored;
 }

+ 8 - 0
applications/nfc/nfc_device.h

@@ -2,6 +2,8 @@
 
 #include <stdint.h>
 #include <stdbool.h>
+#include <storage/storage.h>
+#include <dialogs/dialogs.h>
 
 #include "mifare_ultralight.h"
 
@@ -57,6 +59,8 @@ typedef struct {
 } NfcDeviceData;
 
 typedef struct {
+    Storage* storage;
+    DialogsApp* dialogs;
     NfcDeviceData dev_data;
     char dev_name[NFC_DEV_NAME_MAX_LEN + 1];
     char file_name[NFC_FILE_NAME_MAX_LEN];
@@ -64,6 +68,10 @@ typedef struct {
     bool shadow_file_exist;
 } NfcDevice;
 
+NfcDevice* nfc_device_alloc();
+
+void nfc_device_free(NfcDevice* nfc_dev);
+
 void nfc_device_set_name(NfcDevice* dev, const char* name);
 
 bool nfc_device_save(NfcDevice* dev, const char* dev_name);

+ 0 - 16
applications/nfc/nfc_device_i.h

@@ -1,16 +0,0 @@
-#pragma once
-
-#include "nfc_device.h"
-#include <m-string.h>
-
-uint16_t nfc_device_prepare_format_string(NfcDevice* dev, string_t format_string);
-bool nfc_device_parse_format_string(NfcDevice* dev, string_t format_string);
-
-uint16_t nfc_device_prepare_uid_string(NfcDevice* dev, string_t uid_string);
-bool nfc_device_parse_uid_string(NfcDevice* dev, string_t uid_string);
-
-uint16_t nfc_device_prepare_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string);
-bool nfc_device_parse_mifare_ul_string(NfcDevice* dev, string_t mifare_ul_string);
-
-uint16_t nfc_device_prepare_bank_card_string(NfcDevice* dev, string_t bank_card_string);
-bool nfc_device_parse_bank_card_string(NfcDevice* dev, string_t bank_card_string);

+ 1 - 1
applications/nfc/nfc_i.h

@@ -36,7 +36,7 @@ struct Nfc {
     Gui* gui;
     NotificationApp* notifications;
     SceneManager* scene_manager;
-    NfcDevice dev;
+    NfcDevice* dev;
     NfcDeviceCommonData dev_edit_data;
 
     char text_store[NFC_TEXT_STORE_SIZE + 1];

+ 2 - 0
applications/nfc/nfc_worker.c

@@ -248,6 +248,8 @@ void nfc_worker_read_emv(NfcWorker* nfc_worker) {
                     NFC_WORKER_TAG, "Select PPSE response received. Start parsing response");
                 if(emv_decode_ppse_response(rx_buff, *rx_len, &emv_app)) {
                     FURI_LOG_I(NFC_WORKER_TAG, "Select PPSE responce parced");
+                    result->emv_data.aid_len = emv_app.aid_len;
+                    memcpy(result->emv_data.aid, emv_app.aid, emv_app.aid_len);
                 } else {
                     FURI_LOG_E(NFC_WORKER_TAG, "Can't find pay application");
                     furi_hal_nfc_deactivate();

+ 4 - 4
applications/nfc/scenes/nfc_scene_card_menu.c

@@ -17,7 +17,7 @@ void nfc_scene_card_menu_on_enter(void* context) {
     Nfc* nfc = (Nfc*)context;
     Submenu* submenu = nfc->submenu;
 
-    if(nfc->dev.dev_data.nfc_data.protocol > NfcDeviceProtocolUnknown) {
+    if(nfc->dev->dev_data.nfc_data.protocol > NfcDeviceProtocolUnknown) {
         submenu_add_item(
             submenu,
             "Run compatible app",
@@ -48,9 +48,9 @@ bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) {
         if(event.event == SubmenuIndexRunApp) {
             scene_manager_set_scene_state(
                 nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexRunApp);
-            if(nfc->dev.dev_data.nfc_data.protocol == NfcDeviceProtocolMifareUl) {
+            if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolMifareUl) {
                 scene_manager_next_scene(nfc->scene_manager, NfcSceneReadMifareUl);
-            } else if(nfc->dev.dev_data.nfc_data.protocol == NfcDeviceProtocolEMV) {
+            } else if(nfc->dev->dev_data.nfc_data.protocol == NfcDeviceProtocolEMV) {
                 scene_manager_next_scene(nfc->scene_manager, NfcSceneReadEmvApp);
             }
             return true;
@@ -66,7 +66,7 @@ bool nfc_scene_card_menu_on_event(void* context, SceneManagerEvent event) {
             return true;
         } else if(event.event == SubmenuIndexSave) {
             scene_manager_set_scene_state(nfc->scene_manager, NfcSceneCardMenu, SubmenuIndexSave);
-            nfc->dev.format = NfcDeviceSaveFormatUid;
+            nfc->dev->format = NfcDeviceSaveFormatUid;
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
             return true;
         }

+ 3 - 3
applications/nfc/scenes/nfc_scene_delete.c

@@ -12,14 +12,14 @@ void nfc_scene_delete_on_enter(void* context) {
 
     // Setup Custom Widget view
     char delete_str[64];
-    snprintf(delete_str, sizeof(delete_str), "\e#Delete %s\e#", nfc->dev.dev_name);
+    snprintf(delete_str, sizeof(delete_str), "\e#Delete %s\e#", nfc->dev->dev_name);
     widget_add_text_box_element(nfc->widget, 0, 0, 128, 24, AlignCenter, AlignCenter, delete_str);
     widget_add_button_element(
         nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_delete_widget_callback, nfc);
     widget_add_button_element(
         nfc->widget, GuiButtonTypeRight, "Delete", nfc_scene_delete_widget_callback, nfc);
     char uid_str[32];
-    NfcDeviceCommonData* data = &nfc->dev.dev_data.nfc_data;
+    NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
     if(data->uid_len == 4) {
         snprintf(
             uid_str,
@@ -73,7 +73,7 @@ bool nfc_scene_delete_on_event(void* context, SceneManagerEvent event) {
         if(event.event == GuiButtonTypeLeft) {
             return scene_manager_previous_scene(nfc->scene_manager);
         } else if(event.event == GuiButtonTypeRight) {
-            if(nfc_device_delete(&nfc->dev)) {
+            if(nfc_device_delete(nfc->dev)) {
                 scene_manager_next_scene(nfc->scene_manager, NfcSceneDeleteSuccess);
             } else {
                 scene_manager_search_and_switch_to_previous_scene(

+ 33 - 15
applications/nfc/scenes/nfc_scene_device_info.c

@@ -1,4 +1,5 @@
 #include "../nfc_i.h"
+#include "../helpers/nfc_emv_parser.h"
 
 #define NFC_SCENE_DEVICE_INFO_BACK_EVENT (0UL)
 
@@ -36,13 +37,13 @@ void nfc_scene_device_info_on_enter(void* context) {
 
     // Setup Custom Widget view
     widget_add_text_box_element(
-        nfc->widget, 0, 0, 128, 24, AlignCenter, AlignCenter, nfc->dev.dev_name);
+        nfc->widget, 0, 0, 128, 24, AlignCenter, AlignCenter, nfc->dev->dev_name);
     widget_add_button_element(
         nfc->widget, GuiButtonTypeLeft, "Back", nfc_scene_device_info_widget_callback, nfc);
     widget_add_button_element(
         nfc->widget, GuiButtonTypeRight, "Data", nfc_scene_device_info_widget_callback, nfc);
     char uid_str[32];
-    NfcDeviceCommonData* data = &nfc->dev.dev_data.nfc_data;
+    NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
     if(data->uid_len == 4) {
         snprintf(
             uid_str,
@@ -87,14 +88,14 @@ void nfc_scene_device_info_on_enter(void* context) {
     widget_add_string_element(nfc->widget, 118, 42, AlignRight, AlignTop, FontSecondary, atqa_str);
 
     // Setup Data View
-    if(nfc->dev.format == NfcDeviceSaveFormatUid) {
+    if(nfc->dev->format == NfcDeviceSaveFormatUid) {
         DialogEx* dialog_ex = nfc->dialog_ex;
         dialog_ex_set_left_button_text(dialog_ex, "Back");
         dialog_ex_set_text(dialog_ex, "No data", 64, 32, AlignCenter, AlignCenter);
         dialog_ex_set_context(dialog_ex, nfc);
         dialog_ex_set_result_callback(dialog_ex, nfc_scene_device_info_dialog_callback);
-    } else if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) {
-        MifareUlData* mf_ul_data = (MifareUlData*)&nfc->dev.dev_data.mf_ul_data;
+    } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
+        MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
         TextBox* text_box = nfc->text_box;
         text_box_set_context(text_box, nfc);
         text_box_set_exit_callback(text_box, nfc_scene_device_info_text_box_callback);
@@ -107,8 +108,8 @@ void nfc_scene_device_info_on_enter(void* context) {
                 nfc->text_box_store, "%02X%02X ", mf_ul_data->data[i], mf_ul_data->data[i + 1]);
         }
         text_box_set_text(text_box, string_get_cstr(nfc->text_box_store));
-    } else if(nfc->dev.format == NfcDeviceSaveFormatBankCard) {
-        NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data;
+    } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
+        NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data;
         BankCard* bank_card = nfc->bank_card;
         bank_card_set_name(bank_card, emv_data->name);
         bank_card_set_number(bank_card, emv_data->number, emv_data->number_len);
@@ -116,12 +117,29 @@ void nfc_scene_device_info_on_enter(void* context) {
         if(emv_data->exp_mon) {
             bank_card_set_exp_date(bank_card, emv_data->exp_mon, emv_data->exp_year);
         }
+        string_t display_str;
+        string_init(display_str);
         if(emv_data->country_code) {
-            bank_card_set_country_name(bank_card, emv_data->country_code);
+            string_t country_name;
+            string_init(country_name);
+            if(nfc_emv_parser_get_country_name(
+                   nfc->dev->storage, emv_data->country_code, country_name)) {
+                string_printf(display_str, "Reg:%s", string_get_cstr(country_name));
+                bank_card_set_country_name(bank_card, string_get_cstr(display_str));
+            }
+            string_clear(country_name);
         }
         if(emv_data->currency_code) {
-            bank_card_set_currency_name(bank_card, emv_data->currency_code);
+            string_t currency_name;
+            string_init(currency_name);
+            if(nfc_emv_parser_get_currency_name(
+                   nfc->dev->storage, emv_data->country_code, currency_name)) {
+                string_printf(display_str, "Cur:%s", string_get_cstr(currency_name));
+                bank_card_set_currency_name(bank_card, string_get_cstr(display_str));
+            }
+            string_clear(currency_name);
         }
+        string_clear(display_str);
     }
     scene_manager_set_scene_state(nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoUid);
     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewWidget);
@@ -136,17 +154,17 @@ bool nfc_scene_device_info_on_event(void* context, SceneManagerEvent event) {
         if((state == NfcSceneDeviceInfoUid) && (event.event == GuiButtonTypeLeft)) {
             consumed = scene_manager_previous_scene(nfc->scene_manager);
         } else if((state == NfcSceneDeviceInfoUid) && (event.event == GuiButtonTypeRight)) {
-            if(nfc->dev.format == NfcDeviceSaveFormatUid) {
+            if(nfc->dev->format == NfcDeviceSaveFormatUid) {
                 scene_manager_set_scene_state(
                     nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData);
                 view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewDialogEx);
                 consumed = true;
-            } else if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) {
+            } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
                 scene_manager_set_scene_state(
                     nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData);
                 view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewTextBox);
                 consumed = true;
-            } else if(nfc->dev.format == NfcDeviceSaveFormatBankCard) {
+            } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
                 scene_manager_set_scene_state(
                     nfc->scene_manager, NfcSceneDeviceInfo, NfcSceneDeviceInfoData);
                 view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewBankCard);
@@ -168,7 +186,7 @@ void nfc_scene_device_info_on_exit(void* context) {
     // Clear Custom Widget
     widget_clear(nfc->widget);
 
-    if(nfc->dev.format == NfcDeviceSaveFormatUid) {
+    if(nfc->dev->format == NfcDeviceSaveFormatUid) {
         // Clear Dialog
         DialogEx* dialog_ex = nfc->dialog_ex;
         dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
@@ -179,11 +197,11 @@ void nfc_scene_device_info_on_exit(void* context) {
         dialog_ex_set_center_button_text(dialog_ex, NULL);
         dialog_ex_set_result_callback(dialog_ex, NULL);
         dialog_ex_set_context(dialog_ex, NULL);
-    } else if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) {
+    } else if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
         // Clear TextBox
         text_box_clean(nfc->text_box);
         string_clean(nfc->text_box_store);
-    } else if(nfc->dev.format == NfcDeviceSaveFormatBankCard) {
+    } else if(nfc->dev->format == NfcDeviceSaveFormatBankCard) {
         // Clear Bank Card
         bank_card_clear(nfc->bank_card);
     }

+ 1 - 1
applications/nfc/scenes/nfc_scene_emulate_apdu_sequence.c

@@ -11,7 +11,7 @@ void nfc_scene_emulate_apdu_sequence_on_enter(void* context) {
     // Setup and start worker
 
     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
-    nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev.dev_data, NULL, nfc);
+    nfc_worker_start(nfc->worker, NfcWorkerStateEmulateApdu, &nfc->dev->dev_data, NULL, nfc);
 }
 
 bool nfc_scene_emulate_apdu_sequence_on_event(void* context, SceneManagerEvent event) {

+ 4 - 4
applications/nfc/scenes/nfc_scene_emulate_mifare_ul.c

@@ -14,8 +14,8 @@ void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
 
     // Setup view
     Popup* popup = nfc->popup;
-    if(strcmp(nfc->dev.dev_name, "")) {
-        nfc_text_store_set(nfc, "%s", nfc->dev.dev_name);
+    if(strcmp(nfc->dev->dev_name, "")) {
+        nfc_text_store_set(nfc, "%s", nfc->dev->dev_name);
     }
     popup_set_icon(popup, 0, 3, &I_RFIDDolphinSend_97x61);
     popup_set_header(popup, "Emulating\nMf Ultralight", 56, 31, AlignLeft, AlignTop);
@@ -25,7 +25,7 @@ void nfc_scene_emulate_mifare_ul_on_enter(void* context) {
     nfc_worker_start(
         nfc->worker,
         NfcWorkerStateEmulateMifareUl,
-        &nfc->dev.dev_data,
+        &nfc->dev->dev_data,
         nfc_emulate_mifare_ul_worker_callback,
         nfc);
 }
@@ -45,7 +45,7 @@ bool nfc_scene_emulate_mifare_ul_on_event(void* context, SceneManagerEvent event
            NFC_MF_UL_DATA_CHANGED) {
             scene_manager_set_scene_state(
                 nfc->scene_manager, NfcSceneEmulateMifareUl, NFC_MF_UL_DATA_NOT_CHANGED);
-            nfc_device_save_shadow(&nfc->dev, nfc->dev.dev_name);
+            nfc_device_save_shadow(nfc->dev, nfc->dev->dev_name);
         }
         consumed = false;
     }

+ 4 - 4
applications/nfc/scenes/nfc_scene_emulate_uid.c

@@ -5,10 +5,10 @@ void nfc_scene_emulate_uid_on_enter(void* context) {
 
     // Setup view
     Popup* popup = nfc->popup;
-    NfcDeviceCommonData* data = &nfc->dev.dev_data.nfc_data;
+    NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
 
-    if(strcmp(nfc->dev.dev_name, "")) {
-        nfc_text_store_set(nfc, "%s", nfc->dev.dev_name);
+    if(strcmp(nfc->dev->dev_name, "")) {
+        nfc_text_store_set(nfc, "%s", nfc->dev->dev_name);
     } else if(data->uid_len == 4) {
         nfc_text_store_set(
             nfc, "%02X %02X %02X %02X", data->uid[0], data->uid[1], data->uid[2], data->uid[3]);
@@ -32,7 +32,7 @@ void nfc_scene_emulate_uid_on_enter(void* context) {
     // Setup and start worker
 
     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
-    nfc_worker_start(nfc->worker, NfcWorkerStateEmulate, &nfc->dev.dev_data, NULL, nfc);
+    nfc_worker_start(nfc->worker, NfcWorkerStateEmulate, &nfc->dev->dev_data, NULL, nfc);
 }
 
 bool nfc_scene_emulate_uid_on_event(void* context, SceneManagerEvent event) {

+ 1 - 1
applications/nfc/scenes/nfc_scene_file_select.c

@@ -3,7 +3,7 @@
 void nfc_scene_file_select_on_enter(void* context) {
     Nfc* nfc = (Nfc*)context;
     // Process file_select return
-    if(nfc_file_select(&nfc->dev)) {
+    if(nfc_file_select(nfc->dev)) {
         scene_manager_next_scene(nfc->scene_manager, NfcSceneSavedMenu);
     } else {
         scene_manager_search_and_switch_to_previous_scene(nfc->scene_manager, NfcSceneStart);

+ 2 - 2
applications/nfc/scenes/nfc_scene_mifare_ul_menu.c

@@ -32,9 +32,9 @@ bool nfc_scene_mifare_ul_menu_on_event(void* context, SceneManagerEvent event) {
         if(event.event == SubmenuIndexSave) {
             scene_manager_set_scene_state(
                 nfc->scene_manager, NfcSceneMifareUlMenu, SubmenuIndexSave);
-            nfc->dev.format = NfcDeviceSaveFormatMifareUl;
+            nfc->dev->format = NfcDeviceSaveFormatMifareUl;
             // Clear device name
-            nfc_device_set_name(&nfc->dev, "");
+            nfc_device_set_name(nfc->dev, "");
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
             return true;
         } else if(event.event == SubmenuIndexEmulate) {

+ 1 - 1
applications/nfc/scenes/nfc_scene_read_card.c

@@ -18,7 +18,7 @@ void nfc_scene_read_card_on_enter(void* context) {
     // Start worker
     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
     nfc_worker_start(
-        nfc->worker, NfcWorkerStateDetect, &nfc->dev.dev_data, nfc_read_card_worker_callback, nfc);
+        nfc->worker, NfcWorkerStateDetect, &nfc->dev->dev_data, nfc_read_card_worker_callback, nfc);
 }
 
 bool nfc_scene_read_card_on_event(void* context, SceneManagerEvent event) {

+ 2 - 2
applications/nfc/scenes/nfc_scene_read_card_success.c

@@ -15,7 +15,7 @@ void nfc_scene_read_card_success_on_enter(void* context) {
     notification_message(nfc->notifications, &sequence_success);
 
     // Setup view
-    NfcDeviceCommonData* data = (NfcDeviceCommonData*)&nfc->dev.dev_data.nfc_data;
+    NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
     DialogEx* dialog_ex = nfc->dialog_ex;
     dialog_ex_set_left_button_text(dialog_ex, "Retry");
     dialog_ex_set_right_button_text(dialog_ex, "More");
@@ -68,7 +68,7 @@ bool nfc_scene_read_card_success_on_event(void* context, SceneManagerEvent event
             return scene_manager_previous_scene(nfc->scene_manager);
         } else if(event.event == DialogExResultRight) {
             // Clear device name
-            nfc_device_set_name(&nfc->dev, "");
+            nfc_device_set_name(nfc->dev, "");
             scene_manager_next_scene(nfc->scene_manager, NfcSceneCardMenu);
             return true;
         }

+ 1 - 1
applications/nfc/scenes/nfc_scene_read_emv_app.c

@@ -20,7 +20,7 @@ void nfc_scene_read_emv_app_on_enter(void* context) {
     nfc_worker_start(
         nfc->worker,
         NfcWorkerStateReadEMVApp,
-        &nfc->dev.dev_data,
+        &nfc->dev->dev_data,
         nfc_read_emv_app_worker_callback,
         nfc);
 }

+ 4 - 3
applications/nfc/scenes/nfc_scene_read_emv_app_success.c

@@ -13,8 +13,8 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) {
     Nfc* nfc = (Nfc*)context;
 
     // Setup view
-    NfcDeviceCommonData* nfc_data = &nfc->dev.dev_data.nfc_data;
-    NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data;
+    NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data;
+    NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data;
     DialogEx* dialog_ex = nfc->dialog_ex;
     dialog_ex_set_left_button_text(dialog_ex, "Retry");
     dialog_ex_set_right_button_text(dialog_ex, "Run app");
@@ -23,7 +23,8 @@ void nfc_scene_read_emv_app_success_on_enter(void* context) {
     // Display UID and AID
     string_t aid;
     string_init(aid);
-    bool aid_found = nfc_emv_parser_get_aid_name(emv_data->aid, emv_data->aid_len, aid);
+    bool aid_found =
+        nfc_emv_parser_get_aid_name(nfc->dev->storage, emv_data->aid, emv_data->aid_len, aid);
     if(!aid_found) {
         for(uint8_t i = 0; i < emv_data->aid_len; i++) {
             string_cat_printf(aid, "%02X", emv_data->aid[i]);

+ 2 - 2
applications/nfc/scenes/nfc_scene_read_emv_data.c

@@ -17,12 +17,12 @@ void nfc_scene_read_emv_data_on_enter(void* context) {
 
     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewPopup);
     // Clear emv data
-    memset(&nfc->dev.dev_data.emv_data, 0, sizeof(nfc->dev.dev_data.emv_data));
+    memset(&nfc->dev->dev_data.emv_data, 0, sizeof(nfc->dev->dev_data.emv_data));
     // Start worker
     nfc_worker_start(
         nfc->worker,
         NfcWorkerStateReadEMV,
-        &nfc->dev.dev_data,
+        &nfc->dev->dev_data,
         nfc_read_emv_data_worker_callback,
         nfc);
 }

+ 8 - 7
applications/nfc/scenes/nfc_scene_read_emv_data_success.c

@@ -13,8 +13,8 @@ void nfc_scene_read_emv_data_success_widget_callback(
 
 void nfc_scene_read_emv_data_success_on_enter(void* context) {
     Nfc* nfc = (Nfc*)context;
-    NfcEmvData* emv_data = &nfc->dev.dev_data.emv_data;
-    NfcDeviceCommonData* nfc_data = &nfc->dev.dev_data.nfc_data;
+    NfcEmvData* emv_data = &nfc->dev->dev_data.emv_data;
+    NfcDeviceCommonData* nfc_data = &nfc->dev->dev_data.nfc_data;
 
     // Setup Custom Widget view
     // Add frame
@@ -34,7 +34,7 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
         nfc);
     // Add card name
     widget_add_string_element(
-        nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev.dev_data.emv_data.name);
+        nfc->widget, 64, 3, AlignCenter, AlignTop, FontSecondary, nfc->dev->dev_data.emv_data.name);
     // Add cad number
     string_t pan_str;
     string_init(pan_str);
@@ -49,7 +49,7 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
     string_t country_name;
     string_init(country_name);
     if((emv_data->country_code) &&
-       nfc_emv_parser_get_country_name(emv_data->country_code, country_name)) {
+       nfc_emv_parser_get_country_name(nfc->dev->storage, emv_data->country_code, country_name)) {
         string_t disp_country;
         string_init_printf(disp_country, "Reg:%s", country_name);
         widget_add_string_element(
@@ -61,7 +61,8 @@ void nfc_scene_read_emv_data_success_on_enter(void* context) {
     string_t currency_name;
     string_init(currency_name);
     if((emv_data->currency_code) &&
-       nfc_emv_parser_get_currency_name(emv_data->currency_code, currency_name)) {
+       nfc_emv_parser_get_currency_name(
+           nfc->dev->storage, emv_data->currency_code, currency_name)) {
         string_t disp_currency;
         string_init_printf(disp_currency, "Cur:%s", currency_name);
         widget_add_string_element(
@@ -122,8 +123,8 @@ bool nfc_scene_read_emv_data_success_on_event(void* context, SceneManagerEvent e
                 nfc->scene_manager, NfcSceneReadEmvAppSuccess);
         } else if(event.event == GuiButtonTypeRight) {
             // Clear device name
-            nfc_device_set_name(&nfc->dev, "");
-            nfc->dev.format = NfcDeviceSaveFormatBankCard;
+            nfc_device_set_name(nfc->dev, "");
+            nfc->dev->format = NfcDeviceSaveFormatBankCard;
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveName);
             return true;
         }

+ 1 - 1
applications/nfc/scenes/nfc_scene_read_mifare_ul.c

@@ -20,7 +20,7 @@ void nfc_scene_read_mifare_ul_on_enter(void* context) {
     nfc_worker_start(
         nfc->worker,
         NfcWorkerStateReadMifareUl,
-        &nfc->dev.dev_data,
+        &nfc->dev->dev_data,
         nfc_read_mifare_ul_worker_callback,
         nfc);
 }

+ 2 - 2
applications/nfc/scenes/nfc_scene_read_mifare_ul_success.c

@@ -27,7 +27,7 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
     notification_message(nfc->notifications, &sequence_success);
 
     // Setup dialog view
-    NfcDeviceCommonData* data = (NfcDeviceCommonData*)&nfc->dev.dev_data.nfc_data;
+    NfcDeviceCommonData* data = &nfc->dev->dev_data.nfc_data;
     DialogEx* dialog_ex = nfc->dialog_ex;
     dialog_ex_set_left_button_text(dialog_ex, "Retry");
     dialog_ex_set_right_button_text(dialog_ex, "More");
@@ -54,7 +54,7 @@ void nfc_scene_read_mifare_ul_success_on_enter(void* context) {
     dialog_ex_set_result_callback(dialog_ex, nfc_scene_read_mifare_ul_success_dialog_callback);
 
     // Setup TextBox view
-    MifareUlData* mf_ul_data = (MifareUlData*)&nfc->dev.dev_data.mf_ul_data;
+    MifareUlData* mf_ul_data = &nfc->dev->dev_data.mf_ul_data;
     TextBox* text_box = nfc->text_box;
     text_box_set_context(text_box, nfc);
     text_box_set_exit_callback(text_box, nfc_scene_read_mifare_ul_success_text_box_callback);

+ 7 - 7
applications/nfc/scenes/nfc_scene_save_name.c

@@ -15,11 +15,11 @@ void nfc_scene_save_name_on_enter(void* context) {
     // Setup view
     TextInput* text_input = nfc->text_input;
     bool dev_name_empty = false;
-    if(!strcmp(nfc->dev.dev_name, "")) {
+    if(!strcmp(nfc->dev->dev_name, "")) {
         set_random_name(nfc->text_store, sizeof(nfc->text_store));
         dev_name_empty = true;
     } else {
-        nfc_text_store_set(nfc, nfc->dev.dev_name);
+        nfc_text_store_set(nfc, nfc->dev->dev_name);
     }
     text_input_set_header_text(text_input, "Name the card");
     text_input_set_result_callback(
@@ -37,14 +37,14 @@ bool nfc_scene_save_name_on_event(void* context, SceneManagerEvent event) {
 
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == SCENE_SAVE_NAME_CUSTOM_EVENT) {
-            if(strcmp(nfc->dev.dev_name, "")) {
-                nfc_device_delete(&nfc->dev);
+            if(strcmp(nfc->dev->dev_name, "")) {
+                nfc_device_delete(nfc->dev);
             }
             if(scene_manager_has_previous_scene(nfc->scene_manager, NfcSceneSetUid)) {
-                nfc->dev.dev_data.nfc_data = nfc->dev_edit_data;
+                nfc->dev->dev_data.nfc_data = nfc->dev_edit_data;
             }
-            strlcpy(nfc->dev.dev_name, nfc->text_store, strlen(nfc->text_store) + 1);
-            if(nfc_device_save(&nfc->dev, nfc->text_store)) {
+            strlcpy(nfc->dev->dev_name, nfc->text_store, strlen(nfc->text_store) + 1);
+            if(nfc_device_save(nfc->dev, nfc->text_store)) {
                 scene_manager_next_scene(nfc->scene_manager, NfcSceneSaveSuccess);
                 return true;
             } else {

+ 4 - 4
applications/nfc/scenes/nfc_scene_saved_menu.c

@@ -18,7 +18,7 @@ void nfc_scene_saved_menu_on_enter(void* context) {
     Nfc* nfc = (Nfc*)context;
     Submenu* submenu = nfc->submenu;
 
-    if(nfc->dev.format != NfcDeviceSaveFormatBankCard) {
+    if(nfc->dev->format != NfcDeviceSaveFormatBankCard) {
         submenu_add_item(
             submenu, "Emulate", SubmenuIndexEmulate, nfc_scene_saved_menu_submenu_callback, nfc);
     }
@@ -30,7 +30,7 @@ void nfc_scene_saved_menu_on_enter(void* context) {
         submenu, "Info", SubmenuIndexInfo, nfc_scene_saved_menu_submenu_callback, nfc);
     submenu_set_selected_item(
         nfc->submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneSavedMenu));
-    if(nfc->dev.shadow_file_exist) {
+    if(nfc->dev->shadow_file_exist) {
         submenu_add_item(
             submenu,
             "Restore original",
@@ -49,7 +49,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
     if(event.type == SceneManagerEventTypeCustom) {
         scene_manager_set_scene_state(nfc->scene_manager, NfcSceneSavedMenu, event.event);
         if(event.event == SubmenuIndexEmulate) {
-            if(nfc->dev.format == NfcDeviceSaveFormatMifareUl) {
+            if(nfc->dev->format == NfcDeviceSaveFormatMifareUl) {
                 scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateMifareUl);
             } else {
                 scene_manager_next_scene(nfc->scene_manager, NfcSceneEmulateUid);
@@ -65,7 +65,7 @@ bool nfc_scene_saved_menu_on_event(void* context, SceneManagerEvent event) {
             scene_manager_next_scene(nfc->scene_manager, NfcSceneDeviceInfo);
             consumed = true;
         } else if(event.event == SubmenuIndexRestoreOriginal) {
-            if(!nfc_device_restore(&nfc->dev)) {
+            if(!nfc_device_restore(nfc->dev)) {
                 scene_manager_search_and_switch_to_previous_scene(
                     nfc->scene_manager, NfcSceneStart);
             } else {

+ 1 - 1
applications/nfc/scenes/nfc_scene_set_atqa.c

@@ -19,7 +19,7 @@ void nfc_scene_set_atqa_on_enter(void* context) {
         nfc_scene_set_atqa_byte_input_callback,
         NULL,
         nfc,
-        nfc->dev.dev_data.nfc_data.atqa,
+        nfc->dev->dev_data.nfc_data.atqa,
         2);
     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput);
 }

+ 1 - 1
applications/nfc/scenes/nfc_scene_set_sak.c

@@ -19,7 +19,7 @@ void nfc_scene_set_sak_on_enter(void* context) {
         nfc_scene_set_sak_byte_input_callback,
         NULL,
         nfc,
-        &nfc->dev.dev_data.nfc_data.sak,
+        &nfc->dev->dev_data.nfc_data.sak,
         1);
     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewByteInput);
 }

+ 5 - 5
applications/nfc/scenes/nfc_scene_set_type.c

@@ -15,7 +15,7 @@ void nfc_scene_set_type_on_enter(void* context) {
     Nfc* nfc = (Nfc*)context;
     Submenu* submenu = nfc->submenu;
     // Clear device name
-    nfc_device_set_name(&nfc->dev, "");
+    nfc_device_set_name(nfc->dev, "");
     submenu_add_item(
         submenu, "NFC-A 7-bytes UID", SubmenuIndexNFCA7, nfc_scene_set_type_submenu_callback, nfc);
     submenu_add_item(
@@ -28,13 +28,13 @@ bool nfc_scene_set_type_on_event(void* context, SceneManagerEvent event) {
 
     if(event.type == SceneManagerEventTypeCustom) {
         if(event.event == SubmenuIndexNFCA7) {
-            nfc->dev.dev_data.nfc_data.uid_len = 7;
-            nfc->dev.format = NfcDeviceSaveFormatUid;
+            nfc->dev->dev_data.nfc_data.uid_len = 7;
+            nfc->dev->format = NfcDeviceSaveFormatUid;
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak);
             return true;
         } else if(event.event == SubmenuIndexNFCA4) {
-            nfc->dev.dev_data.nfc_data.uid_len = 4;
-            nfc->dev.format = NfcDeviceSaveFormatUid;
+            nfc->dev->dev_data.nfc_data.uid_len = 4;
+            nfc->dev->format = NfcDeviceSaveFormatUid;
             scene_manager_next_scene(nfc->scene_manager, NfcSceneSetSak);
             return true;
         }

+ 1 - 1
applications/nfc/scenes/nfc_scene_set_uid.c

@@ -14,7 +14,7 @@ void nfc_scene_set_uid_on_enter(void* context) {
     // Setup view
     ByteInput* byte_input = nfc->byte_input;
     byte_input_set_header_text(byte_input, "Enter uid in hex");
-    nfc->dev_edit_data = nfc->dev.dev_data.nfc_data;
+    nfc->dev_edit_data = nfc->dev->dev_data.nfc_data;
     byte_input_set_result_callback(
         byte_input,
         nfc_scene_set_uid_byte_input_callback,

+ 1 - 1
applications/nfc/scenes/nfc_scene_start.c

@@ -34,7 +34,7 @@ void nfc_scene_start_on_enter(void* context) {
     submenu_set_selected_item(
         submenu, scene_manager_get_scene_state(nfc->scene_manager, NfcSceneStart));
 
-    nfc_device_clear(&nfc->dev);
+    nfc_device_clear(nfc->dev);
     view_dispatcher_switch_to_view(nfc->view_dispatcher, NfcViewMenu);
 }
 

+ 6 - 34
applications/nfc/views/bank_card.c

@@ -67,42 +67,14 @@ void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year) {
         bank_card->widget, 122, 54, AlignRight, AlignBottom, FontSecondary, exp_date_str);
 }
 
-void bank_card_set_country_name(BankCard* bank_card, uint16_t country_code) {
+void bank_card_set_country_name(BankCard* bank_card, const char* country_name) {
     furi_assert(bank_card);
-    string_t country_name;
-    string_init(country_name);
-    if(nfc_emv_parser_get_country_name(country_code, country_name)) {
-        string_t disp_country;
-        string_init_printf(disp_country, "Reg:%s", country_name);
-        widget_add_string_element(
-            bank_card->widget,
-            120,
-            18,
-            AlignRight,
-            AlignTop,
-            FontSecondary,
-            string_get_cstr(disp_country));
-        string_clear(disp_country);
-    }
-    string_clear(country_name);
+    widget_add_string_element(
+        bank_card->widget, 120, 18, AlignRight, AlignTop, FontSecondary, country_name);
 }
 
-void bank_card_set_currency_name(BankCard* bank_card, uint16_t currency_code) {
+void bank_card_set_currency_name(BankCard* bank_card, const char* currency_name) {
     furi_assert(bank_card);
-    string_t currency_name;
-    string_init(currency_name);
-    if(nfc_emv_parser_get_currency_name(currency_code, currency_name)) {
-        string_t disp_currency;
-        string_init_printf(disp_currency, "Cur:%s", currency_name);
-        widget_add_string_element(
-            bank_card->widget,
-            31,
-            18,
-            AlignLeft,
-            AlignTop,
-            FontSecondary,
-            string_get_cstr(disp_currency));
-        string_clear(disp_currency);
-    }
-    string_clear(currency_name);
+    widget_add_string_element(
+        bank_card->widget, 31, 18, AlignLeft, AlignTop, FontSecondary, currency_name);
 }

+ 2 - 2
applications/nfc/views/bank_card.h

@@ -21,6 +21,6 @@ void bank_card_set_number(BankCard* bank_card, uint8_t* number, uint8_t len);
 
 void bank_card_set_exp_date(BankCard* bank_card, uint8_t mon, uint8_t year);
 
-void bank_card_set_country_name(BankCard* bank_card, uint16_t country_code);
+void bank_card_set_country_name(BankCard* bank_card, const char* country_name);
 
-void bank_card_set_currency_name(BankCard* bank_card, uint16_t currency_code);
+void bank_card_set_currency_name(BankCard* bank_card, const char* currency_name);

+ 151 - 148
assets/resources/nfc/emv/aid.nfc

@@ -1,148 +1,151 @@
-A00000000305076010 VISA ELO Credit
-A0000000031010 VISA Debit/Credit (Classic)
-A000000003101001 VISA Credit
-A000000003101002 VISA Debit
-A0000000032010 VISA Electron
-A0000000032020 VISA
-A0000000033010 VISA Interlink
-A0000000034010 VISA Specific
-A0000000035010 VISA Specific
-A0000000036010 Domestic Visa Cash
-A0000000036020 International Visa Cash
-A0000000038002 VISA Auth EMV-CAP (DPA)
-A0000000038010 VISA Plus
-A0000000039010 VISA Loyalty
-A000000003999910 VISA Proprietary ATM
-A00000000401 MasterCard PayPass
-A0000000041010 MasterCard Global
-A00000000410101213 MasterCard Credit
-A00000000410101215 MasterCard Credit
-A0000000042010 MasterCard Specific
-A0000000043010 MasterCard Specific
-A0000000043060 Maestro (Debit)
-A000000004306001 Maestro (Debit)
-A0000000044010 MasterCard Specific
-A0000000045010 MasterCard Specific
-A0000000046000 Cirrus
-A0000000048002 SecureCode EMV-CAP
-A0000000049999 MasterCard PayPass
-A0000000050001 Maestro UK
-A0000000050002 Solo
-A00000002401 Self Service
-A000000025 American Express
-A0000000250000 American Express
-A00000002501 American Express
-A000000025010402 American Express
-A000000025010701 ExpressPay
-A000000025010801 American Express
-A0000000291010 Link / American Express
-A0000000421010 Cartes Bancaire EMV Card
-A0000000426010 Apple Pay
-A00000006510 JCB
-A0000000651010 JCB J Smart Credit
-A00000006900 Moneo
-A000000077010000021000000000003B Visa AEPN
-A000000098 Debit Card
-A0000000980848 Debit Card
-A0000001211010 Dankort VISA GEM Vision
-A0000001410001 PagoBANCOMAT
-A0000001523010 Discover, Pulse D Pas
-A0000001524010 Discover
-A0000001544442 Banricompras Debito
-A000000172950001 BAROC Taiwan
-A0000002281010 SPAN (M/Chip)
-A0000002282010 SPAN (VIS)
-A0000002771010 INTERAC
-A00000031510100528 Currence PuC
-A0000003156020 Chipknip
-A0000003591010028001 Girocard EAPS
-A0000003710001 InterSwitch Verve Card
-A0000004540010 Etranzact Genesis Card
-A0000004540011 Etranzact Genesis Card 2
-A0000004766C GOOGLE_PAYMENT
-A0000005241010 RuPay
-A0000006723010 TROY chip credit card
-A0000006723020 TROY chip debit card
-A0000007705850 XTRAPOWER
-B012345678 Maestro TEST
-D27600002545500100 Girocard
-D5780000021010 Bankaxept
-F0000000030001 BRADESCO
-A000000003000000 (VISA) Card Manager
-A000000003534441 Schlumberger SD
-A0000000035350 Security Domain
-A000000003535041 Security Domain
-A0000000040000 MasterCard Card Manager
-A000000018434D Gemplus card manager
-A000000018434D00 Gemplus Security Domain
-A0000000960200 Proton WISD
-A0000001510000 Global Platform SD
-A00000015153504341534400 CASD_AID
-A000000476A010 GSD_MANAGER_AID
-A000000476A110 GSD_MANAGER_AID
-315041592E5359532E4444463031 Visa PSE 
-325041592E5359532E4444463031 Visa PPSE
-A0000000042203 MasterCard Specific
-A0000000045555 APDULogger
-A0000000090001FF44FF1289 Orange
-A0000000101030 Maestro-CH
-A00000001800 Gemplus
-A0000000181001 gemplus util packages
-A000000025010104 American Express
-A00000002949034010100001 HSBC
-A00000002949282010100000 Barclay
-A00000005945430100 Girocard Electronic Cash
-A0000000980840 Visa Common Debit
-A0000001570010 AMEX
-A0000001570020 MasterCard
-A0000001570021 Maestro
-A0000001570022 Maestro
-A0000001570023 CASH
-A0000001570030 VISA
-A0000001570031 VISA
-A0000001570040 JCB
-A0000001570050 Postcard
-A0000001570051 Postcard
-A0000001570100 MCard
-A0000001570104 MyOne
-A000000157010C WIRCard
-A000000157010D Power Card
-A0000001574443 DINERS CLUB
-A0000001574444 Supercard Plus
-A00000022820101010 SPAN
-A000000308000010000100 ID-ONE PIV BIO
-A0000003241010 Discover Zip
-A000000333010101 UnionPay Debit
-A000000333010102 UnionPay Credit
-A000000333010103 UnionPay Quasi Credit
-A000000333010106 UnionPay Electronic Cash
-A000000333010108 U.S. UnionPay Common Debit
-A000000337102000 Classic
-A000000337101001 Prepaye Online
-A000000337102001 Prepaye Possibile Offiline
-A000000337601001 Porte Monnaie Electronique
-A0000006581010 MIR Credit
-A0000006581011 MIR Credit
-A0000006582010 MIR Debit
-D040000001000002 Paylife Quick IEP
-D040000002000002 RFU
-D040000003000002 POS
-D040000004000002 ATM
-D04000000B000002 Retail
-D04000000C000002 Bank_Data
-D04000000D000002 Shopping
-D040000013000001 DF_UNI_Kepler1
-D040000013000001 DF_Schüler1
-D040000013000002 DF_UNI_Kepler2
-D040000013000002 DF_Schüler2
-D040000014000001 DF_Mensa
-D040000015000001 DF_UNI_Ausweis
-D040000015000001 DF_Ausweis
-D0400000190001 EMV ATM Maestro
-D0400000190002 EMV POS Maestro
-D0400000190003 EMV ATM MasterCard
-D0400000190004 EMV POS MasterCard
-D276000025 Girocard
-D27600002547410100 Girocard ATM
-D7560000010101 Reka Card
-D7560000300101 M Budget
+Filetype: Flipper EMV resources
+Version: 1
+# EMV Application ID code: Application ID name
+A00000000305076010: VISA ELO Credit
+A0000000031010: VISA Debit/Credit (Classic)
+A000000003101001: VISA Credit
+A000000003101002: VISA Debit
+A0000000032010: VISA Electron
+A0000000032020: VISA
+A0000000033010: VISA Interlink
+A0000000034010: VISA Specific
+A0000000035010: VISA Specific
+A0000000036010: Domestic Visa Cash
+A0000000036020: International Visa Cash
+A0000000038002: VISA Auth EMV-CAP (DPA)
+A0000000038010: VISA Plus
+A0000000039010: VISA Loyalty
+A000000003999910: VISA Proprietary ATM
+A00000000401: MasterCard PayPass
+A0000000041010: MasterCard Global
+A00000000410101213: MasterCard Credit
+A00000000410101215: MasterCard Credit
+A0000000042010: MasterCard Specific
+A0000000043010: MasterCard Specific
+A0000000043060: Maestro (Debit)
+A000000004306001: Maestro (Debit)
+A0000000044010: MasterCard Specific
+A0000000045010: MasterCard Specific
+A0000000046000: Cirrus
+A0000000048002: SecureCode EMV-CAP
+A0000000049999: MasterCard PayPass
+A0000000050001: Maestro UK
+A0000000050002: Solo
+A00000002401: Self Service
+A000000025: American Express
+A0000000250000: American Express
+A00000002501: American Express
+A000000025010402: American Express
+A000000025010701: ExpressPay
+A000000025010801: American Express
+A0000000291010: Link / American Express
+A0000000421010: Cartes Bancaire EMV Card
+A0000000426010: Apple Pay
+A00000006510: JCB
+A0000000651010: JCB J Smart Credit
+A00000006900: Moneo
+A000000077010000021000000000003B: Visa AEPN
+A000000098: Debit Card
+A0000000980848: Debit Card
+A0000001211010: Dankort VISA GEM Vision
+A0000001410001: PagoBANCOMAT
+A0000001523010: Discover, Pulse D Pas
+A0000001524010: Discover
+A0000001544442: Banricompras Debito
+A000000172950001: BAROC Taiwan
+A0000002281010: SPAN (M/Chip)
+A0000002282010: SPAN (VIS)
+A0000002771010: INTERAC
+A00000031510100528: Currence PuC
+A0000003156020: Chipknip
+A0000003591010028001: Girocard EAPS
+A0000003710001: InterSwitch Verve Card
+A0000004540010: Etranzact Genesis Card
+A0000004540011: Etranzact Genesis Card 2
+A0000004766C: GOOGLE_PAYMENT
+A0000005241010: RuPay
+A0000006723010: TROY chip credit card
+A0000006723020: TROY chip debit card
+A0000007705850: XTRAPOWER
+B012345678: Maestro TEST
+D27600002545500100: Girocard
+D5780000021010: Bankaxept
+F0000000030001: BRADESCO
+A000000003000000: (VISA) Card Manager
+A000000003534441: Schlumberger SD
+A0000000035350: Security Domain
+A000000003535041: Security Domain
+A0000000040000: MasterCard Card Manager
+A000000018434D: Gemplus card manager
+A000000018434D00: Gemplus Security Domain
+A0000000960200: Proton WISD
+A0000001510000: Global Platform SD
+A00000015153504341534400: CASD_AID
+A000000476A010: GSD_MANAGER_AID
+A000000476A110: GSD_MANAGER_AID
+315041592E5359532E4444463031: Visa PSE 
+325041592E5359532E4444463031: Visa PPSE
+A0000000042203: MasterCard Specific
+A0000000045555: APDULogger
+A0000000090001FF44FF1289: Orange
+A0000000101030: Maestro-CH
+A00000001800: Gemplus
+A0000000181001: gemplus util packages
+A000000025010104: American Express
+A00000002949034010100001: HSBC
+A00000002949282010100000: Barclay
+A00000005945430100: Girocard Electronic Cash
+A0000000980840: Visa Common Debit
+A0000001570010: AMEX
+A0000001570020: MasterCard
+A0000001570021: Maestro
+A0000001570022: Maestro
+A0000001570023: CASH
+A0000001570030: VISA
+A0000001570031: VISA
+A0000001570040: JCB
+A0000001570050: Postcard
+A0000001570051: Postcard
+A0000001570100: MCard
+A0000001570104: MyOne
+A000000157010C: WIRCard
+A000000157010D: Power Card
+A0000001574443: DINERS CLUB
+A0000001574444: Supercard Plus
+A00000022820101010: SPAN
+A000000308000010000100: ID-ONE PIV BIO
+A0000003241010: Discover Zip
+A000000333010101: UnionPay Debit
+A000000333010102: UnionPay Credit
+A000000333010103: UnionPay Quasi Credit
+A000000333010106: UnionPay Electronic Cash
+A000000333010108: U.S. UnionPay Common Debit
+A000000337102000: Classic
+A000000337101001: Prepaye Online
+A000000337102001: Prepaye Possibile Offiline
+A000000337601001: Porte Monnaie Electronique
+A0000006581010: MIR Credit
+A0000006581011: MIR Credit
+A0000006582010: MIR Debit
+D040000001000002: Paylife Quick IEP
+D040000002000002: RFU
+D040000003000002: POS
+D040000004000002: ATM
+D04000000B000002: Retail
+D04000000C000002: Bank_Data
+D04000000D000002: Shopping
+D040000013000001: DF_UNI_Kepler1
+D040000013000001: DF_Schüler1
+D040000013000002: DF_UNI_Kepler2
+D040000013000002: DF_Schüler2
+D040000014000001: DF_Mensa
+D040000015000001: DF_UNI_Ausweis
+D040000015000001: DF_Ausweis
+D0400000190001: EMV ATM Maestro
+D0400000190002: EMV POS Maestro
+D0400000190003: EMV ATM MasterCard
+D0400000190004: EMV POS MasterCard
+D276000025: Girocard
+D27600002547410100: Girocard ATM
+D7560000010101: Reka Card
+D7560000300101: M Budget

+ 252 - 249
assets/resources/nfc/emv/country_code.nfc

@@ -1,249 +1,252 @@
-0004 AFG
-0008 ALB
-0010 ATA
-0012 DZA
-0016 ASM
-0020 AND
-0024 AGO
-0028 ATG
-0031 AZE
-0032 ARG
-0036 AUS
-0040 AUT
-0044 BHS
-0048 BHR
-0050 BGD
-0051 ARM
-0052 BRB
-0056 BEL
-0060 BMU
-0064 BTN
-0068 BOL
-0070 BIH
-0072 BWA
-0074 BVT
-0076 BRA
-0084 BLZ
-0086 IOT
-0090 SLB
-0092 VGB
-0096 BRN
-0100 BGR
-0104 MMR
-0108 BDI
-0112 BLR
-0116 KHM
-0120 CMR
-0124 CAN
-0132 CPV
-0136 CYM
-0140 CAF
-0144 LKA
-0148 TCD
-0152 CHL
-0156 CHN
-0158 TWN
-0162 CXR
-0166 CCK
-0170 COL
-0174 COM
-0175 MYT
-0178 COG
-0180 COD
-0184 COK
-0188 CRI
-0191 HRV
-0192 CUB
-0196 CYP
-0203 CZE
-0204 BEN
-0208 DNK
-0212 DMA
-0214 DOM
-0218 ECU
-0222 SLV
-0226 GNQ
-0231 ETH
-0232 ERI
-0233 EST
-0234 FRO
-0238 FLK
-0239 SGS
-0242 FJI
-0246 FIN
-0248 ALA
-0250 FRA
-0254 GUF
-0258 PYF
-0260 ATF
-0262 DJI
-0266 GAB
-0268 GEO
-0270 GMB
-0275 PSE
-0276 DEU
-0288 GHA
-0292 GIB
-0296 KIR
-0300 GRC
-0304 GRL
-0308 GRD
-0312 GLP
-0316 GUM
-0320 GTM
-0324 GIN
-0328 GUY
-0332 HTI
-0334 HMD
-0336 VAT
-0340 HND
-0344 HKG
-0348 HUN
-0352 ISL
-0356 IND
-0360 IDN
-0364 IRN
-0368 IRQ
-0372 IRL
-0376 ISR
-0380 ITA
-0384 CIV
-0388 JAM
-0392 JPN
-0398 KAZ
-0400 JOR
-0404 KEN
-0408 PRK
-0410 KOR
-0414 KWT
-0417 KGZ
-0418 LAO
-0422 LBN
-0426 LSO
-0428 LVA
-0430 LBR
-0434 LBY
-0438 LIE
-0440 LTU
-0442 LUX
-0446 MAC
-0450 MDG
-0454 MWI
-0458 MYS
-0462 MDV
-0466 MLI
-0470 MLT
-0474 MTQ
-0478 MRT
-0480 MUS
-0484 MEX
-0492 MCO
-0496 MNG
-0498 MDA
-0499 MNE
-0500 MSR
-0504 MAR
-0508 MOZ
-0512 OMN
-0516 NAM
-0520 NRU
-0524 NPL
-0528 NLD
-0531 CUW
-0533 ABW
-0534 SXM
-0535 BES
-0540 NCL
-0548 VUT
-0554 NZL
-0558 NIC
-0562 NER
-0566 NGA
-0570 NIU
-0574 NFK
-0578 NOR
-0580 MNP
-0581 UMI
-0583 FSM
-0584 MHL
-0585 PLW
-0586 PAK
-0591 PAN
-0598 PNG
-0600 PRY
-0604 PER
-0608 PHL
-0612 PCN
-0616 POL
-0620 PRT
-0624 GNB
-0626 TLS
-0630 PRI
-0634 QAT
-0638 REU
-0642 ROU
-0643 RUS
-0646 RWA
-0652 BLM
-0654 SHN
-0659 KNA
-0660 AIA
-0662 LCA
-0663 MAF
-0666 SPM
-0670 VCT
-0674 SMR
-0678 STP
-0682 SAU
-0686 SEN
-0688 SRB
-0690 SYC
-0694 SLE
-0702 SGP
-0703 SVK
-0704 VNM
-0705 SVN
-0706 SOM
-0710 ZAF
-0716 ZWE
-0724 ESP
-0728 SSD
-0729 SDN
-0732 ESH
-0740 SUR
-0744 SJM
-0748 SWZ
-0752 SWE
-0756 CHE
-0760 SYR
-0762 TJK
-0764 THA
-0768 TGO
-0772 TKL
-0776 TON
-0780 TTO
-0784 ARE
-0788 TUN
-0792 TUR
-0795 TKM
-0796 TCA
-0798 TUV
-0800 UGA
-0804 UKR
-0807 MKD
-0818 EGY
-0826 GBR
-0831 GGY
-0832 JEY
-0833 IMN
-0834 TZA
-0840 USA
-0850 VIR
-0854 BFA
-0858 URY
-0860 UZB
-0862 VEN
-0876 WLF
-0882 WSM
-0887 YEM
-0894 ZMB
+Filetype: Flipper EMV resources
+Version: 1
+# EMV country code: country name
+0004: AFG
+0008: ALB
+0010: ATA
+0012: DZA
+0016: ASM
+0020: AND
+0024: AGO
+0028: ATG
+0031: AZE
+0032: ARG
+0036: AUS
+0040: AUT
+0044: BHS
+0048: BHR
+0050: BGD
+0051: ARM
+0052: BRB
+0056: BEL
+0060: BMU
+0064: BTN
+0068: BOL
+0070: BIH
+0072: BWA
+0074: BVT
+0076: BRA
+0084: BLZ
+0086: IOT
+0090: SLB
+0092: VGB
+0096: BRN
+0100: BGR
+0104: MMR
+0108: BDI
+0112: BLR
+0116: KHM
+0120: CMR
+0124: CAN
+0132: CPV
+0136: CYM
+0140: CAF
+0144: LKA
+0148: TCD
+0152: CHL
+0156: CHN
+0158: TWN
+0162: CXR
+0166: CCK
+0170: COL
+0174: COM
+0175: MYT
+0178: COG
+0180: COD
+0184: COK
+0188: CRI
+0191: HRV
+0192: CUB
+0196: CYP
+0203: CZE
+0204: BEN
+0208: DNK
+0212: DMA
+0214: DOM
+0218: ECU
+0222: SLV
+0226: GNQ
+0231: ETH
+0232: ERI
+0233: EST
+0234: FRO
+0238: FLK
+0239: SGS
+0242: FJI
+0246: FIN
+0248: ALA
+0250: FRA
+0254: GUF
+0258: PYF
+0260: ATF
+0262: DJI
+0266: GAB
+0268: GEO
+0270: GMB
+0275: PSE
+0276: DEU
+0288: GHA
+0292: GIB
+0296: KIR
+0300: GRC
+0304: GRL
+0308: GRD
+0312: GLP
+0316: GUM
+0320: GTM
+0324: GIN
+0328: GUY
+0332: HTI
+0334: HMD
+0336: VAT
+0340: HND
+0344: HKG
+0348: HUN
+0352: ISL
+0356: IND
+0360: IDN
+0364: IRN
+0368: IRQ
+0372: IRL
+0376: ISR
+0380: ITA
+0384: CIV
+0388: JAM
+0392: JPN
+0398: KAZ
+0400: JOR
+0404: KEN
+0408: PRK
+0410: KOR
+0414: KWT
+0417: KGZ
+0418: LAO
+0422: LBN
+0426: LSO
+0428: LVA
+0430: LBR
+0434: LBY
+0438: LIE
+0440: LTU
+0442: LUX
+0446: MAC
+0450: MDG
+0454: MWI
+0458: MYS
+0462: MDV
+0466: MLI
+0470: MLT
+0474: MTQ
+0478: MRT
+0480: MUS
+0484: MEX
+0492: MCO
+0496: MNG
+0498: MDA
+0499: MNE
+0500: MSR
+0504: MAR
+0508: MOZ
+0512: OMN
+0516: NAM
+0520: NRU
+0524: NPL
+0528: NLD
+0531: CUW
+0533: ABW
+0534: SXM
+0535: BES
+0540: NCL
+0548: VUT
+0554: NZL
+0558: NIC
+0562: NER
+0566: NGA
+0570: NIU
+0574: NFK
+0578: NOR
+0580: MNP
+0581: UMI
+0583: FSM
+0584: MHL
+0585: PLW
+0586: PAK
+0591: PAN
+0598: PNG
+0600: PRY
+0604: PER
+0608: PHL
+0612: PCN
+0616: POL
+0620: PRT
+0624: GNB
+0626: TLS
+0630: PRI
+0634: QAT
+0638: REU
+0642: ROU
+0643: RUS
+0646: RWA
+0652: BLM
+0654: SHN
+0659: KNA
+0660: AIA
+0662: LCA
+0663: MAF
+0666: SPM
+0670: VCT
+0674: SMR
+0678: STP
+0682: SAU
+0686: SEN
+0688: SRB
+0690: SYC
+0694: SLE
+0702: SGP
+0703: SVK
+0704: VNM
+0705: SVN
+0706: SOM
+0710: ZAF
+0716: ZWE
+0724: ESP
+0728: SSD
+0729: SDN
+0732: ESH
+0740: SUR
+0744: SJM
+0748: SWZ
+0752: SWE
+0756: CHE
+0760: SYR
+0762: TJK
+0764: THA
+0768: TGO
+0772: TKL
+0776: TON
+0780: TTO
+0784: ARE
+0788: TUN
+0792: TUR
+0795: TKM
+0796: TCA
+0798: TUV
+0800: UGA
+0804: UKR
+0807: MKD
+0818: EGY
+0826: GBR
+0831: GGY
+0832: JEY
+0833: IMN
+0834: TZA
+0840: USA
+0850: VIR
+0854: BFA
+0858: URY
+0860: UZB
+0862: VEN
+0876: WLF
+0882: WSM
+0887: YEM
+0894: ZMB

+ 171 - 168
assets/resources/nfc/emv/currency_code.nfc

@@ -1,168 +1,171 @@
-0997 USN
-0994 XSU
-0990 CLF
-0986 BRL
-0985 PLN
-0984 BOV
-0981 GEL
-0980 UAH
-0979 MXV
-0978 EUR
-0977 BAM
-0976 CDF
-0975 BGN
-0973 AOA
-0972 TJS
-0971 AFN
-0970 COU
-0969 MGA
-0968 SRD
-0967 ZMW
-0965 XUA
-0960 XDR
-0953 XPF
-0952 XOF
-0951 XCD
-0950 XAF
-0949 TRY
-0948 CHW
-0947 CHE
-0946 RON
-0944 AZN
-0943 MZN
-0941 RSD
-0940 UYI
-0938 SDG
-0937 VEF
-0936 GHS
-0934 TMT
-0933 BYN
-0932 ZWL
-0931 CUC
-0930 STN
-0929 MRU
-0901 TWD
-0886 YER
-0882 WST
-0860 UZS
-0858 UYU
-0840 USD
-0834 TZS
-0826 GBP
-0818 EGP
-0807 MKD
-0800 UGX
-0788 TND
-0784 AED
-0780 TTD
-0776 TOP
-0764 THB
-0760 SYP
-0756 CHF
-0752 SEK
-0748 SZL
-0728 SSP
-0710 ZAR
-0706 SOS
-0704 VND
-0702 SGD
-0694 SLL
-0690 SCR
-0682 SAR
-0654 SHP
-0646 RWF
-0643 RUB
-0634 QAR
-0608 PHP
-0604 PEN
-0600 PYG
-0598 PGK
-0590 PAB
-0586 PKR
-0578 NOK
-0566 NGN
-0558 NIO
-0554 NZD
-0548 VUV
-0533 AWG
-0532 ANG
-0524 NPR
-0516 NAD
-0512 OMR
-0504 MAD
-0498 MDL
-0496 MNT
-0484 MXN
-0480 MUR
-0462 MVR
-0458 MYR
-0454 MWK
-0446 MOP
-0434 LYD
-0430 LRD
-0426 LSL
-0422 LBP
-0418 LAK
-0417 KGS
-0414 KWD
-0410 KRW
-0408 KPW
-0404 KES
-0400 JOD
-0398 KZT
-0392 JPY
-0388 JMD
-0376 ILS
-0368 IQD
-0364 IRR
-0360 IDR
-0356 INR
-0352 ISK
-0348 HUF
-0344 HKD
-0340 HNL
-0332 HTG
-0328 GYD
-0324 GNF
-0320 GTQ
-0292 GIP
-0270 GMD
-0262 DJF
-0242 FJD
-0238 FKP
-0232 ERN
-0230 ETB
-0222 SVC
-0214 DOP
-0208 DKK
-0203 CZK
-0192 CUP
-0191 HRK
-0188 CRC
-0174 KMF
-0170 COP
-0156 CNY
-0152 CLP
-0144 LKR
-0136 KYD
-0132 CVE
-0124 CAD
-0116 KHR
-0108 BIF
-0104 MMK
-0096 BND
-0090 SBD
-0084 BZD
-0072 BWP
-0068 BOB
-0064 BTN
-0060 BMD
-0052 BBD
-0051 AMD
-0050 BDT
-0048 BHD
-0044 BSD
-0036 AUD
-0032 ARS
-0012 DZD
-0008 ALL
+Filetype: Flipper EMV resources
+Version: 1
+# EMV currency code: currency name
+0997: USN
+0994: XSU
+0990: CLF
+0986: BRL
+0985: PLN
+0984: BOV
+0981: GEL
+0980: UAH
+0979: MXV
+0978: EUR
+0977: BAM
+0976: CDF
+0975: BGN
+0973: AOA
+0972: TJS
+0971: AFN
+0970: COU
+0969: MGA
+0968: SRD
+0967: ZMW
+0965: XUA
+0960: XDR
+0953: XPF
+0952: XOF
+0951: XCD
+0950: XAF
+0949: TRY
+0948: CHW
+0947: CHE
+0946: RON
+0944: AZN
+0943: MZN
+0941: RSD
+0940: UYI
+0938: SDG
+0937: VEF
+0936: GHS
+0934: TMT
+0933: BYN
+0932: ZWL
+0931: CUC
+0930: STN
+0929: MRU
+0901: TWD
+0886: YER
+0882: WST
+0860: UZS
+0858: UYU
+0840: USD
+0834: TZS
+0826: GBP
+0818: EGP
+0807: MKD
+0800: UGX
+0788: TND
+0784: AED
+0780: TTD
+0776: TOP
+0764: THB
+0760: SYP
+0756: CHF
+0752: SEK
+0748: SZL
+0728: SSP
+0710: ZAR
+0706: SOS
+0704: VND
+0702: SGD
+0694: SLL
+0690: SCR
+0682: SAR
+0654: SHP
+0646: RWF
+0643: RUB
+0634: QAR
+0608: PHP
+0604: PEN
+0600: PYG
+0598: PGK
+0590: PAB
+0586: PKR
+0578: NOK
+0566: NGN
+0558: NIO
+0554: NZD
+0548: VUV
+0533: AWG
+0532: ANG
+0524: NPR
+0516: NAD
+0512: OMR
+0504: MAD
+0498: MDL
+0496: MNT
+0484: MXN
+0480: MUR
+0462: MVR
+0458: MYR
+0454: MWK
+0446: MOP
+0434: LYD
+0430: LRD
+0426: LSL
+0422: LBP
+0418: LAK
+0417: KGS
+0414: KWD
+0410: KRW
+0408: KPW
+0404: KES
+0400: JOD
+0398: KZT
+0392: JPY
+0388: JMD
+0376: ILS
+0368: IQD
+0364: IRR
+0360: IDR
+0356: INR
+0352: ISK
+0348: HUF
+0344: HKD
+0340: HNL
+0332: HTG
+0328: GYD
+0324: GNF
+0320: GTQ
+0292: GIP
+0270: GMD
+0262: DJF
+0242: FJD
+0238: FKP
+0232: ERN
+0230: ETB
+0222: SVC
+0214: DOP
+0208: DKK
+0203: CZK
+0192: CUP
+0191: HRK
+0188: CRC
+0174: KMF
+0170: COP
+0156: CNY
+0152: CLP
+0144: LKR
+0136: KYD
+0132: CVE
+0124: CAD
+0116: KHR
+0108: BIF
+0104: MMK
+0096: BND
+0090: SBD
+0084: BZD
+0072: BWP
+0068: BOB
+0064: BTN
+0060: BMD
+0052: BBD
+0051: AMD
+0050: BDT
+0048: BHD
+0044: BSD
+0036: AUD
+0032: ARS
+0012: DZD
+0008: ALL