From 70db616c04283e787d7162b53dbc0c66c569fadc Mon Sep 17 00:00:00 2001 From: Willy-JL <49810075+Willy-JL@users.noreply.github.com> Date: Wed, 29 May 2024 07:50:53 +0100 Subject: [PATCH] Archive: New info page with md5 hash --- ChangeLog.md | 1 + .../main/archive/scenes/archive_scene_info.c | 111 ++++++++++++++---- 2 files changed, 88 insertions(+), 24 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index b6dcca256d..f031ef8a78 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -13,6 +13,7 @@ - GPIO: Pokemon Trading (by @EstebanFuentealba) - GPIO: Badge (by @jamisonderek) - Tools: Tone Generator (by @GEMISIS) +- Archive: New info page with md5 hash (by @Willy-JL) - OFW: NFC: Add Slix capabilities, some bugfixes (by @gornekich) - OFW: JS: Added `math.is_equal()` and `math.EPSILON` (by @skotopes) diff --git a/applications/main/archive/scenes/archive_scene_info.c b/applications/main/archive/scenes/archive_scene_info.c index 14725eaed6..0e6ce7ed06 100644 --- a/applications/main/archive/scenes/archive_scene_info.c +++ b/applications/main/archive/scenes/archive_scene_info.c @@ -1,5 +1,6 @@ #include "../archive_i.h" #include "../helpers/archive_browser.h" +#include #define TAG "Archive" @@ -13,7 +14,7 @@ void archive_scene_info_widget_callback(GuiButtonType result, InputType type, vo } } -uint32_t archive_scene_info_dirwalk(void* context) { +static uint32_t archive_scene_info_dirwalk(void* context) { furi_assert(context); ArchiveApp* instance = context; @@ -26,8 +27,7 @@ uint32_t archive_scene_info_dirwalk(void* context) { while(scene_manager_get_scene_state(instance->scene_manager, ArchiveAppSceneInfo)) { DirWalkResult result = dir_walk_read(dir_walk, NULL, &fileinfo); if(result == DirWalkError) { - snprintf(buf, sizeof(buf), "Size: \e#Error\e#"); - widget_element_text_box_set_text(instance->element, buf); + widget_element_text_box_set_text(instance->element, "Size: \e#Error\e#"); break; } bool is_last = result == DirWalkLast; @@ -51,8 +51,7 @@ uint32_t archive_scene_info_dirwalk(void* context) { if(is_last) break; } } else { - snprintf(buf, sizeof(buf), "Size: \e#Error\e#"); - widget_element_text_box_set_text(instance->element, buf); + widget_element_text_box_set_text(instance->element, "Size: \e#Error\e#"); } dir_walk_free(dir_walk); furi_record_close(RECORD_STORAGE); @@ -61,6 +60,64 @@ uint32_t archive_scene_info_dirwalk(void* context) { return 0; } +static uint32_t archive_scene_info_md5sum(void* context) { + furi_assert(context); + ArchiveApp* instance = context; + + // Based on lib/toolbox/md5_calc.c + File* file = storage_file_alloc(furi_record_open(RECORD_STORAGE)); + ArchiveFile_t* current = archive_get_current_file(instance->browser); + bool result = false; + if(storage_file_open( + file, furi_string_get_cstr(current->path), FSAM_READ, FSOM_OPEN_EXISTING)) { + uint8_t output[16]; + const size_t size_to_read = 512; + uint8_t* data = malloc(size_to_read); + mbedtls_md5_context* md5_ctx = malloc(sizeof(mbedtls_md5_context)); + mbedtls_md5_init(md5_ctx); + mbedtls_md5_starts(md5_ctx); + while(scene_manager_get_scene_state(instance->scene_manager, ArchiveAppSceneInfo)) { + size_t read_size = storage_file_read(file, data, size_to_read); + if(storage_file_get_error(file) != FSE_OK) { + break; + } + if(read_size == 0) { + result = true; + break; + } + mbedtls_md5_update(md5_ctx, data, read_size); + } + mbedtls_md5_finish(md5_ctx, output); + if(result) { + FuriString* md5 = furi_string_alloc_set("MD5: \e*"); + for(size_t i = 0; i < sizeof(output); i++) { + furi_string_cat_printf(md5, "%02x", output[i]); + } + furi_string_cat(md5, "\e*"); + widget_element_text_box_set_text(instance->element, furi_string_get_cstr(md5)); + } + free(md5_ctx); + free(data); + storage_file_close(file); + } + storage_file_free(file); + furi_record_close(RECORD_STORAGE); + + if(!result) { + char buf[64]; + strlcpy(buf, "MD5: \e*Error", sizeof(buf)); + uint8_t padding = 32 - strlen("Error"); + for(uint8_t i = 0; i < padding; i++) { + strlcat(buf, " ", sizeof(buf)); + } + strlcat(buf, "\e*", sizeof(buf)); + widget_element_text_box_set_text(instance->element, buf); + } + + view_dispatcher_switch_to_view(instance->view_dispatcher, ArchiveViewWidget); + return 0; +} + void archive_scene_info_on_enter(void* context) { furi_assert(context); ArchiveApp* instance = context; @@ -77,21 +134,12 @@ void archive_scene_info_on_enter(void* context) { // Filename path_extract_filename(current->path, filename, false); snprintf(buf, sizeof(buf), "\e#%s\e#", furi_string_get_cstr(filename)); - widget_add_text_box_element( - instance->widget, 0, 0, 128, 24, AlignLeft, AlignCenter, buf, false); + widget_add_text_box_element(instance->widget, 1, 1, 126, 13, AlignLeft, AlignTop, buf, true); // Directory path path_extract_dirname(furi_string_get_cstr(current->path), dirname); widget_add_text_box_element( - instance->widget, - 0, - 42, - 128, - 12, - AlignLeft, - AlignCenter, - furi_string_get_cstr(dirname), - false); + instance->widget, 1, 12, 126, 20, AlignLeft, AlignTop, furi_string_get_cstr(dirname), true); // This one to return and cursor select this file path_extract_filename_no_ext(furi_string_get_cstr(current->path), filename); @@ -125,18 +173,33 @@ void archive_scene_info_on_enter(void* context) { show, units[unit]); } - instance->element = widget_add_text_box_element( - instance->widget, 0, 24, 128, 24, AlignLeft, AlignCenter, buf, true); + WidgetElement* element = widget_add_text_box_element( + instance->widget, 1, 31, 126, 13, AlignLeft, AlignTop, buf, true); + + // MD5 hash + if(!is_dir) { + strlcpy(buf, "MD5: \e*Loading...", sizeof(buf)); + uint8_t padding = 32 - strlen("Loading..."); + for(uint8_t i = 0; i < padding; i++) { + strlcat(buf, " ", sizeof(buf)); + } + strlcat(buf, "\e*", sizeof(buf)); + element = widget_add_text_box_element( + instance->widget, 0, 43, 128, 24, AlignRight, AlignTop, buf, false); + } + + instance->element = element; furi_record_close(RECORD_STORAGE); view_dispatcher_switch_to_view(instance->view_dispatcher, ArchiveViewWidget); - if(is_dir) { - scene_manager_set_scene_state(instance->scene_manager, ArchiveAppSceneInfo, true); - instance->thread = furi_thread_alloc_ex( - "ArchiveInfoDirWalk", 1024, (FuriThreadCallback)archive_scene_info_dirwalk, instance); - furi_thread_start(instance->thread); - } + scene_manager_set_scene_state(instance->scene_manager, ArchiveAppSceneInfo, true); + instance->thread = furi_thread_alloc_ex( + "ArchiveInfoWorker", + 1024, + (FuriThreadCallback)(is_dir ? archive_scene_info_dirwalk : archive_scene_info_md5sum), + instance); + furi_thread_start(instance->thread); } bool archive_scene_info_on_event(void* context, SceneManagerEvent event) {