| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769 |
- /*
- * @Author: SpenserCai
- * @Date: 2025-02-28 17:52:49
- * @version:
- * @LastEditors: SpenserCai
- * @LastEditTime: 2025-03-16 19:59:42
- * @Description: file content
- */
- #include "nfc_apdu_runner.h"
- #include "scenes/nfc_apdu_runner_scene.h"
- // 菜单项枚举
- typedef enum {
- NfcApduRunnerSubmenuIndexLoadFile,
- NfcApduRunnerSubmenuIndexViewLogs,
- NfcApduRunnerSubmenuIndexAbout,
- } NfcApduRunnerSubmenuIndex;
- // 前向声明
- static void nfc_apdu_runner_free(NfcApduRunner* app);
- static NfcApduRunner* nfc_apdu_runner_alloc();
- static void nfc_apdu_runner_init(NfcApduRunner* app);
- static bool nfc_apdu_runner_custom_event_callback(void* context, uint32_t event);
- static bool nfc_apdu_runner_back_event_callback(void* context);
- static void nfc_apdu_runner_tick_event_callback(void* context);
- // 释放APDU脚本资源
- void nfc_apdu_script_free(NfcApduScript* script) {
- if(script == NULL) return;
- for(uint32_t i = 0; i < script->command_count; i++) {
- free(script->commands[i]);
- }
- free(script);
- }
- // 释放APDU响应资源
- void nfc_apdu_responses_free(NfcApduResponse* responses, uint32_t count) {
- if(responses == NULL) return;
- for(uint32_t i = 0; i < count; i++) {
- free(responses[i].command);
- free(responses[i].response);
- }
- free(responses);
- }
- // 解析卡类型字符串
- static CardType parse_card_type(const char* type_str) {
- if(strcmp(type_str, "iso14443_3a") == 0) {
- return CardTypeIso14443_3a;
- } else if(strcmp(type_str, "iso14443_3b") == 0) {
- return CardTypeIso14443_3b;
- } else if(strcmp(type_str, "iso14443_4a") == 0) {
- return CardTypeIso14443_4a;
- } else if(strcmp(type_str, "iso14443_4b") == 0) {
- return CardTypeIso14443_4b;
- } else {
- return CardTypeUnknown;
- }
- }
- // 解析APDU脚本文件
- NfcApduScript* nfc_apdu_script_parse(Storage* storage, const char* file_path) {
- FURI_LOG_I("APDU_DEBUG", "开始解析脚本文件: %s", file_path);
- if(!storage || !file_path) {
- FURI_LOG_E("APDU_DEBUG", "无效的存储或文件路径");
- return NULL;
- }
- NfcApduScript* script = malloc(sizeof(NfcApduScript));
- if(!script) {
- FURI_LOG_E("APDU_DEBUG", "分配脚本内存失败");
- return NULL;
- }
- memset(script, 0, sizeof(NfcApduScript));
- FuriString* temp_str = furi_string_alloc();
- if(!temp_str) {
- FURI_LOG_E("APDU_DEBUG", "分配临时字符串内存失败");
- free(script);
- return NULL;
- }
- File* file = storage_file_alloc(storage);
- if(!file) {
- FURI_LOG_E("APDU_DEBUG", "分配文件失败");
- furi_string_free(temp_str);
- free(script);
- return NULL;
- }
- bool success = false;
- bool in_data_section = false;
- do {
- if(!storage_file_open(file, file_path, FSAM_READ, FSOM_OPEN_EXISTING)) {
- FURI_LOG_E("APDU_DEBUG", "打开文件失败: %s", file_path);
- break;
- }
- // 读取整个文件内容到缓冲区
- char file_buf[1024];
- size_t bytes_read = storage_file_read(file, file_buf, sizeof(file_buf) - 1);
- if(bytes_read <= 0) {
- FURI_LOG_E("APDU_DEBUG", "读取文件内容失败");
- break;
- }
- file_buf[bytes_read] = '\0';
- FURI_LOG_I("APDU_DEBUG", "读取文件内容成功, 大小: %zu 字节", bytes_read);
- // 解析文件内容
- char* line = file_buf;
- char* next_line;
- // 读取文件类型行
- next_line = strchr(line, '\n');
- if(!next_line) {
- FURI_LOG_E("APDU_DEBUG", "文件格式错误,找不到换行符");
- break;
- }
- *next_line = '\0';
- if(strncmp(line, "Filetype: APDU Script", 21) != 0) {
- FURI_LOG_E("APDU_DEBUG", "无效的文件类型: %s", line);
- break;
- }
- // 读取版本行
- line = next_line + 1;
- next_line = strchr(line, '\n');
- if(!next_line) {
- FURI_LOG_E("APDU_DEBUG", "文件格式错误,找不到版本行结束");
- break;
- }
- *next_line = '\0';
- if(strncmp(line, "Version: 1", 10) != 0) {
- FURI_LOG_E("APDU_DEBUG", "无效的版本: %s", line);
- break;
- }
- // 读取卡类型行
- line = next_line + 1;
- next_line = strchr(line, '\n');
- if(!next_line) {
- FURI_LOG_E("APDU_DEBUG", "文件格式错误,找不到卡类型行结束");
- break;
- }
- *next_line = '\0';
- if(strncmp(line, "CardType: ", 10) != 0) {
- FURI_LOG_E("APDU_DEBUG", "无效的卡类型行: %s", line);
- break;
- }
- // 提取卡类型
- const char* card_type_str = line + 10; // 跳过 "CardType: "
- script->card_type = parse_card_type(card_type_str);
- if(script->card_type == CardTypeUnknown) {
- FURI_LOG_E("APDU_DEBUG", "不支持的卡类型: %s", card_type_str);
- break;
- }
- FURI_LOG_I("APDU_DEBUG", "卡类型解析成功: %s", card_type_str);
- // 读取数据行
- line = next_line + 1;
- next_line = strchr(line, '\n');
- // 检查当前行是否为 Data 行
- if(strncmp(line, "Data: [", 7) != 0) {
- FURI_LOG_E("APDU_DEBUG", "无效的数据行: %s", line);
- break;
- }
- in_data_section = true;
- // 解析命令数组
- char* data_str = line + 7; // 跳过 "Data: ["
- // 处理多行格式的命令
- // 将整个文件内容中的所有换行符和空格替换为空格,以便正确解析命令
- char* p = data_str;
- while(*p) {
- if(*p == '\n' || *p == '\r') {
- *p = ' '; // 将换行符替换为空格
- }
- p++;
- }
- // 清理多余的空格,使解析更加稳健
- p = data_str;
- char* q = data_str;
- bool in_quotes = false;
- while(*p) {
- // 在引号内保留所有字符
- if(*p == '"') {
- in_quotes = !in_quotes;
- *q++ = *p++;
- continue;
- }
- // 在引号外,跳过空格
- if(!in_quotes && (*p == ' ' || *p == '\t')) {
- p++;
- continue;
- }
- // 复制其他字符
- *q++ = *p++;
- }
- *q = '\0'; // 确保字符串正确终止
- // 查找第一个引号
- char* command_start = strchr(data_str, '"');
- if(!command_start) {
- FURI_LOG_E("APDU_DEBUG", "未找到命令开始引号");
- break;
- }
- while(command_start != NULL && script->command_count < MAX_APDU_COMMANDS) {
- command_start++; // 跳过开始的引号
- // 查找结束引号
- char* command_end = strchr(command_start, '"');
- if(!command_end) {
- FURI_LOG_E("APDU_DEBUG", "未找到命令结束引号");
- break;
- }
- size_t command_len = command_end - command_start;
- if(command_len == 0) {
- // 空命令,跳过
- FURI_LOG_W("APDU_DEBUG", "空命令,跳过");
- command_start = strchr(command_end + 1, '"');
- continue;
- }
- // 验证命令是否只包含十六进制字符
- bool valid_hex = true;
- for(size_t i = 0; i < command_len; i++) {
- char c = command_start[i];
- if(!((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'))) {
- valid_hex = false;
- break;
- }
- }
- if(!valid_hex) {
- FURI_LOG_E(
- "APDU_DEBUG", "无效的十六进制命令: %.*s", (int)command_len, command_start);
- command_start = strchr(command_end + 1, '"');
- continue;
- }
- // 命令长度必须是偶数
- if(command_len % 2 != 0) {
- FURI_LOG_E(
- "APDU_DEBUG", "命令长度必须是偶数: %.*s", (int)command_len, command_start);
- command_start = strchr(command_end + 1, '"');
- continue;
- }
- // 分配内存并复制命令
- script->commands[script->command_count] = malloc(command_len + 1);
- if(!script->commands[script->command_count]) {
- FURI_LOG_E("APDU_DEBUG", "分配命令内存失败");
- break;
- }
- strncpy(script->commands[script->command_count], command_start, command_len);
- script->commands[script->command_count][command_len] = '\0';
- script->command_count++;
- // 查找下一个命令
- command_start = strchr(command_end + 1, '"');
- }
- success = in_data_section && (script->command_count > 0);
- FURI_LOG_I("APDU_DEBUG", "命令解析完成, 命令数: %lu", script->command_count);
- } while(false);
- storage_file_close(file);
- storage_file_free(file);
- furi_string_free(temp_str);
- if(!success) {
- FURI_LOG_E("APDU_DEBUG", "解析失败,释放脚本资源");
- nfc_apdu_script_free(script);
- return NULL;
- }
- FURI_LOG_I("APDU_DEBUG", "脚本解析成功");
- return script;
- }
- // 保存APDU响应结果
- bool nfc_apdu_save_responses(
- Storage* storage,
- const char* file_path,
- NfcApduResponse* responses,
- uint32_t response_count,
- const char* custom_save_path) {
- FuriString* temp_str = furi_string_alloc();
- FuriString* file_path_str = furi_string_alloc_set(file_path);
- FuriString* response_path = furi_string_alloc();
- // 构建响应文件路径
- if(custom_save_path != NULL) {
- // 使用自定义保存路径
- furi_string_set(response_path, custom_save_path);
- } else {
- // 使用默认路径
- FuriString* filename = furi_string_alloc();
- path_extract_filename(file_path_str, filename, true);
- furi_string_cat_printf(
- response_path,
- "%s/%s%s",
- APP_DIRECTORY_PATH,
- furi_string_get_cstr(filename),
- RESPONSE_EXTENSION);
- furi_string_free(filename);
- }
- File* file = storage_file_alloc(storage);
- bool success = false;
- do {
- if(!storage_file_open(
- file, furi_string_get_cstr(response_path), FSAM_WRITE, FSOM_CREATE_ALWAYS))
- break;
- // 写入文件头
- furi_string_printf(temp_str, "Filetype: APDU Script Response\n");
- if(!storage_file_write(file, furi_string_get_cstr(temp_str), furi_string_size(temp_str)))
- break;
- furi_string_printf(temp_str, "Response:\n");
- if(!storage_file_write(file, furi_string_get_cstr(temp_str), furi_string_size(temp_str)))
- break;
- // 写入每个命令和响应
- for(uint32_t i = 0; i < response_count; i++) {
- furi_string_printf(temp_str, "In: %s\n", responses[i].command);
- if(!storage_file_write(
- file, furi_string_get_cstr(temp_str), furi_string_size(temp_str)))
- break;
- furi_string_printf(temp_str, "Out: ");
- if(!storage_file_write(
- file, furi_string_get_cstr(temp_str), furi_string_size(temp_str)))
- break;
- // 将响应数据转换为十六进制字符串
- for(uint16_t j = 0; j < responses[i].response_length; j++) {
- furi_string_printf(temp_str, "%02X", responses[i].response[j]);
- if(!storage_file_write(
- file, furi_string_get_cstr(temp_str), furi_string_size(temp_str)))
- break;
- }
- furi_string_printf(temp_str, "\n");
- if(!storage_file_write(
- file, furi_string_get_cstr(temp_str), furi_string_size(temp_str)))
- break;
- }
- success = true;
- } while(false);
- storage_file_close(file);
- storage_file_free(file);
- furi_string_free(temp_str);
- furi_string_free(file_path_str);
- furi_string_free(response_path);
- return success;
- }
- // 添加日志
- void add_log_entry(NfcApduRunner* app, const char* message, bool is_error) {
- if(app->log_count >= MAX_LOG_ENTRIES) {
- // 移除最旧的日志
- free(app->log_entries[0].message);
- for(uint32_t i = 0; i < app->log_count - 1; i++) {
- app->log_entries[i] = app->log_entries[i + 1];
- }
- app->log_count--;
- }
- app->log_entries[app->log_count].message = strdup(message);
- app->log_entries[app->log_count].is_error = is_error;
- app->log_count++;
- }
- // 释放日志资源
- void free_logs(NfcApduRunner* app) {
- if(!app) {
- return;
- }
- if(!app->log_entries) {
- return;
- }
- for(uint32_t i = 0; i < app->log_count; i++) {
- if(app->log_entries[i].message) {
- free(app->log_entries[i].message);
- app->log_entries[i].message = NULL;
- }
- }
- app->log_count = 0;
- }
- // 视图分发器回调
- static bool nfc_apdu_runner_custom_event_callback(void* context, uint32_t event) {
- furi_assert(context);
- NfcApduRunner* app = context;
- bool handled = scene_manager_handle_custom_event(app->scene_manager, event);
- return handled;
- }
- static bool nfc_apdu_runner_back_event_callback(void* context) {
- furi_assert(context);
- NfcApduRunner* app = context;
- // 直接交给场景管理器处理返回事件
- bool handled = scene_manager_handle_back_event(app->scene_manager);
- return handled;
- }
- static void nfc_apdu_runner_tick_event_callback(void* context) {
- furi_assert(context);
- NfcApduRunner* app = context;
- scene_manager_handle_tick_event(app->scene_manager);
- }
- // 分配应用程序资源
- static NfcApduRunner* nfc_apdu_runner_alloc() {
- NfcApduRunner* app = malloc(sizeof(NfcApduRunner));
- if(!app) {
- return NULL;
- }
- memset(app, 0, sizeof(NfcApduRunner));
- // 分配GUI资源
- app->gui = furi_record_open(RECORD_GUI);
- if(!app->gui) {
- nfc_apdu_runner_free(app);
- return NULL;
- }
- app->view_dispatcher = view_dispatcher_alloc();
- if(!app->view_dispatcher) {
- nfc_apdu_runner_free(app);
- return NULL;
- }
- app->scene_manager = scene_manager_alloc(&nfc_apdu_runner_scene_handlers, app);
- if(!app->scene_manager) {
- nfc_apdu_runner_free(app);
- return NULL;
- }
- app->submenu = submenu_alloc();
- if(!app->submenu) {
- nfc_apdu_runner_free(app);
- return NULL;
- }
- app->dialogs = furi_record_open(RECORD_DIALOGS);
- if(!app->dialogs) {
- nfc_apdu_runner_free(app);
- return NULL;
- }
- app->widget = widget_alloc();
- if(!app->widget) {
- nfc_apdu_runner_free(app);
- return NULL;
- }
- app->text_box = text_box_alloc();
- if(!app->text_box) {
- nfc_apdu_runner_free(app);
- return NULL;
- }
- app->text_box_store = furi_string_alloc();
- if(!app->text_box_store) {
- nfc_apdu_runner_free(app);
- return NULL;
- }
- app->popup = popup_alloc();
- if(!app->popup) {
- nfc_apdu_runner_free(app);
- return NULL;
- }
- app->button_menu = button_menu_alloc();
- if(!app->button_menu) {
- nfc_apdu_runner_free(app);
- return NULL;
- }
- app->text_input = text_input_alloc();
- if(!app->text_input) {
- nfc_apdu_runner_free(app);
- return NULL;
- }
- // 分配NFC资源
- app->nfc = nfc_alloc();
- if(!app->nfc) {
- nfc_apdu_runner_free(app);
- return NULL;
- }
- // 分配NFC Worker
- app->worker = nfc_worker_alloc(app->nfc);
- if(!app->worker) {
- nfc_apdu_runner_free(app);
- return NULL;
- }
- // 分配存储资源
- app->storage = furi_record_open(RECORD_STORAGE);
- if(!app->storage) {
- nfc_apdu_runner_free(app);
- return NULL;
- }
- app->file_path = furi_string_alloc();
- if(!app->file_path) {
- nfc_apdu_runner_free(app);
- return NULL;
- }
- // 设置默认目录为APP_DIRECTORY_PATH
- furi_string_set(app->file_path, APP_DIRECTORY_PATH);
- // 分配日志资源
- app->log_entries = malloc(sizeof(LogEntry) * MAX_LOG_ENTRIES);
- if(!app->log_entries) {
- nfc_apdu_runner_free(app);
- return NULL;
- }
- app->log_count = 0;
- return app;
- }
- // 释放应用程序资源
- static void nfc_apdu_runner_free(NfcApduRunner* app) {
- if(!app) {
- return;
- }
- // 释放脚本和响应资源
- if(app->script) {
- nfc_apdu_script_free(app->script);
- app->script = NULL;
- }
- if(app->responses) {
- nfc_apdu_responses_free(app->responses, app->response_count);
- app->responses = NULL;
- app->response_count = 0;
- }
- // 先释放所有视图
- if(app->submenu) {
- view_dispatcher_remove_view(app->view_dispatcher, NfcApduRunnerViewSubmenu);
- submenu_free(app->submenu);
- app->submenu = NULL;
- }
- if(app->widget) {
- view_dispatcher_remove_view(app->view_dispatcher, NfcApduRunnerViewWidget);
- widget_free(app->widget);
- app->widget = NULL;
- }
- if(app->text_box) {
- view_dispatcher_remove_view(app->view_dispatcher, NfcApduRunnerViewTextBox);
- text_box_free(app->text_box);
- app->text_box = NULL;
- }
- if(app->text_box_store) {
- furi_string_free(app->text_box_store);
- app->text_box_store = NULL;
- }
- if(app->popup) {
- view_dispatcher_remove_view(app->view_dispatcher, NfcApduRunnerViewPopup);
- popup_free(app->popup);
- app->popup = NULL;
- }
- if(app->button_menu) {
- button_menu_free(app->button_menu);
- app->button_menu = NULL;
- }
- if(app->text_input) {
- view_dispatcher_remove_view(app->view_dispatcher, NfcApduRunnerViewTextInput);
- text_input_free(app->text_input);
- app->text_input = NULL;
- }
- // 关闭记录
- if(app->dialogs) {
- furi_record_close(RECORD_DIALOGS);
- app->dialogs = NULL;
- }
- if(app->gui) {
- furi_record_close(RECORD_GUI);
- app->gui = NULL;
- }
- // 释放NFC资源
- if(app->nfc) {
- nfc_free(app->nfc);
- app->nfc = NULL;
- }
- // 释放NFC Worker
- if(app->worker) {
- nfc_worker_free(app->worker);
- app->worker = NULL;
- }
- // 释放存储资源
- if(app->file_path) {
- furi_string_free(app->file_path);
- app->file_path = NULL;
- }
- if(app->storage) {
- furi_record_close(RECORD_STORAGE);
- app->storage = NULL;
- }
- // 释放日志资源
- free_logs(app);
- if(app->log_entries) {
- free(app->log_entries);
- app->log_entries = NULL;
- }
- // 先释放场景管理器
- if(app->scene_manager) {
- scene_manager_free(app->scene_manager);
- app->scene_manager = NULL;
- }
- // 最后处理视图分发器
- if(app->view_dispatcher) {
- view_dispatcher_free(app->view_dispatcher);
- app->view_dispatcher = NULL;
- FURI_LOG_I("APDU_DEBUG", "View dispatcher freed");
- }
- // 释放应用程序资源
- free(app);
- }
- // 初始化应用程序
- static void nfc_apdu_runner_init(NfcApduRunner* app) {
- if(!app) {
- return;
- }
- // 检查视图分发器是否已分配
- if(!app->view_dispatcher) {
- return;
- }
- // 配置视图分发器
- view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
- view_dispatcher_set_custom_event_callback(
- app->view_dispatcher, nfc_apdu_runner_custom_event_callback);
- view_dispatcher_set_navigation_event_callback(
- app->view_dispatcher, nfc_apdu_runner_back_event_callback);
- view_dispatcher_set_tick_event_callback(
- app->view_dispatcher, nfc_apdu_runner_tick_event_callback, 100);
- // 检查GUI是否已分配
- if(!app->gui) {
- return;
- }
- view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
- // 检查视图组件是否已分配
- if(!app->submenu || !app->widget || !app->text_box || !app->popup || !app->text_input) {
- return;
- }
- // 添加视图
- view_dispatcher_add_view(
- app->view_dispatcher, NfcApduRunnerViewSubmenu, submenu_get_view(app->submenu));
- view_dispatcher_add_view(
- app->view_dispatcher, NfcApduRunnerViewWidget, widget_get_view(app->widget));
- view_dispatcher_add_view(
- app->view_dispatcher, NfcApduRunnerViewTextBox, text_box_get_view(app->text_box));
- view_dispatcher_add_view(
- app->view_dispatcher, NfcApduRunnerViewPopup, popup_get_view(app->popup));
- view_dispatcher_add_view(
- app->view_dispatcher, NfcApduRunnerViewTextInput, text_input_get_view(app->text_input));
- // 配置文本框
- text_box_set_font(app->text_box, TextBoxFontText);
- // 检查存储是否已分配
- if(!app->storage) {
- return;
- }
- // 确保应用目录存在
- if(!storage_dir_exists(app->storage, APP_DIRECTORY_PATH)) {
- if(!storage_simply_mkdir(app->storage, APP_DIRECTORY_PATH)) {
- FURI_LOG_E("APDU_DEBUG", "无法创建应用目录");
- return;
- }
- }
- // 启动场景管理器
- scene_manager_next_scene(app->scene_manager, NfcApduRunnerSceneStart);
- }
- // 应用程序入口点
- int32_t nfc_apdu_runner_app(void* p) {
- UNUSED(p);
- furi_hal_power_suppress_charge_enter();
- // 分配应用程序资源
- NfcApduRunner* app = nfc_apdu_runner_alloc();
- if(!app) {
- return -1;
- }
- // 初始化应用程序
- nfc_apdu_runner_init(app);
- // 运行事件循环
- view_dispatcher_run(app->view_dispatcher);
- // 释放应用程序资源
- nfc_apdu_runner_free(app);
- furi_hal_power_suppress_charge_exit();
- return 0;
- }
|