From d674d5d52c118066b38c3ff39669438d69cc1386 Mon Sep 17 00:00:00 2001 From: fvanroie <15969459+fvanroie@users.noreply.github.com> Date: Sun, 20 Jun 2021 00:31:34 +0200 Subject: [PATCH] Add unzip command --- src/hasp/hasp_dispatch.cpp | 5 +- src/hasp_filesystem.cpp | 113 +++++++++++++++++++++++++++++++++++++ src/hasp_filesystem.h | 19 +++++++ 3 files changed, 136 insertions(+), 1 deletion(-) diff --git a/src/hasp/hasp_dispatch.cpp b/src/hasp/hasp_dispatch.cpp index 04aacbdc..d812d877 100644 --- a/src/hasp/hasp_dispatch.cpp +++ b/src/hasp/hasp_dispatch.cpp @@ -40,7 +40,7 @@ dispatch_conf_t dispatch_setings = {.teleperiod = 300}; uint16_t dispatchSecondsToNextTeleperiod = 0; uint8_t nCommands = 0; -haspCommand_t commands[21]; +haspCommand_t commands[22]; moodlight_t moodlight = {.brightness = 255}; @@ -1081,6 +1081,9 @@ void dispatchSetup() dispatch_add_command(PSTR("screenshot"), dispatch_screenshot); dispatch_add_command(PSTR("discovery"), dispatch_send_discovery); dispatch_add_command(PSTR("factoryreset"), dispatch_factory_reset); +#if HASP_USE_SPIFFS > 0 || HASP_USE_LITTLEFS > 0 + dispatch_add_command(PSTR("unzip"), filesystemUnzip); +#endif #if HASP_USE_CONFIG > 0 dispatch_add_command(PSTR("setupap"), oobeFakeSetup); #endif diff --git a/src/hasp_filesystem.cpp b/src/hasp_filesystem.cpp index 1d640a01..c7b20fe0 100644 --- a/src/hasp_filesystem.cpp +++ b/src/hasp_filesystem.cpp @@ -11,6 +11,7 @@ #include "hasp_debug.h" #include "hasp_filesystem.h" +#include "rom/crc.h" void filesystemInfo() { // Get all information of your SPIFFS @@ -25,6 +26,118 @@ void filesystemInfo() #endif } +void filesystemUnzip(const char*, const char* filename) +{ + File zipfile = HASP_FS.open(filename, FILE_READ); + if(!zipfile) { + return; + } + + int32_t head; + size_t len; + bool done = false; + + zipfile.seek(0); + while(!done) { + len = zipfile.read((uint8_t*)&head, sizeof(head)); + if(len != sizeof(head)) { + done = true; + continue; + } + + switch(head) { + case 0x04034b50: { + zip_file_header_t fh; + zipfile.seek(zipfile.position() - 2, SeekSet); // rewind for struct alignment (26-28) + len = zipfile.read((uint8_t*)(&fh), sizeof(zip_file_header_t)); + if(len != sizeof(zip_file_header_t)) { + done = true; + continue; + } + + if(fh.filename_length >= 31) { + LOG_WARNING(TAG_FILE, F("filename length too long %d"), fh.filename_length); + zipfile.seek(fh.filename_length + fh.extra_length, SeekCur); // skip extra field + continue; + // } else { + // LOG_WARNING(TAG_FILE, F("min %d - flag %d - len %d - xtra %d"), fh.min_version, fh.flags, + // fh.filename_length, fh.extra_length); + } + char name[32] = {0}; + name[0] = '/'; + + len = zipfile.read((uint8_t*)&name[1], fh.filename_length); + if(len != fh.filename_length) { + LOG_WARNING(TAG_FILE, F("filename read failed %d != %d"), fh.filename_length, len); + done = true; + continue; + } + zipfile.seek(fh.extra_length, SeekCur); // skip extra field + + if(fh.compression_method != ZIP_NO_COMPRESSION) { + LOG_WARNING(TAG_FILE, F("Compression is not supported %d"), fh.compression_method); + zipfile.seek(fh.compressed_size, SeekCur); // skip compressed file + } else { + + if(HASP_FS.exists(name)) HASP_FS.remove(name); + + File f = HASP_FS.open(name, FILE_WRITE); + if(f) { + uint8_t buffer[512]; + uint32_t crc32 = 0; + + while(!done && fh.compressed_size >= 512) { + len = zipfile.readBytes((char*)&buffer, 512); + if(len != 512) done = true; + fh.compressed_size -= len; + crc32 = crc32_le(crc32, buffer, len); + // crc2 = crc32_be(crc2, buffer, len); + f.write(buffer, len); + } + + if(!done && fh.compressed_size > 0) { + len = zipfile.readBytes((char*)&buffer, fh.compressed_size); + if(len != fh.compressed_size) done = true; + fh.compressed_size -= len; + crc32 = crc32_le(crc32, buffer, len); + // crc2 = crc32_be(crc2, buffer, len); + f.write(buffer, len); + } + + if(crc32 != fh.crc) done = true; + + if(!done) { + Parser::format_bytes(fh.uncompressed_size, (char*)buffer, sizeof(buffer)); + LOG_VERBOSE(TAG_FILE, F(D_BULLET "%s (%s)"), name, buffer); + } else { + LOG_ERROR(TAG_FILE, F(D_FILE_SAVE_FAILED), name); + } + + f.close(); + } + } + + break; + } + case 0x02014b50: + done = true; + break; + case 0x06054b50: + // end of file + done = true; + break; + default: { + char outputString[9]; + itoa(head, outputString, 16); + LOG_WARNING(TAG_FILE, F("invalid %s"), outputString); + done = true; + } + } + } + zipfile.close(); + LOG_VERBOSE(TAG_FILE, F("extracting %s complete"), filename); +} + void filesystemList() { #if HASP_USE_SPIFFS > 0 diff --git a/src/hasp_filesystem.h b/src/hasp_filesystem.h index bda556ed..62f7da60 100644 --- a/src/hasp_filesystem.h +++ b/src/hasp_filesystem.h @@ -10,6 +10,25 @@ bool filesystemSetup(void); void filesystemList(); void filesystemInfo(); +void filesystemUnzip(const char*, const char* filename); + +enum { ZIP_NO_COMPRESSION = 0, ZIP_DEFLTATE = 8 }; +typedef uint16_t zip_compression_method_t; + +typedef struct +{ + uint16_t dummy_bytes; // total struct needs to be a multiple of 4 bytes + uint16_t min_version; + uint16_t flags; + zip_compression_method_t compression_method; + uint16_t time_modified; + uint16_t date_modified; + uint32_t crc; + uint32_t compressed_size; + uint32_t uncompressed_size; + uint16_t filename_length; // OK + uint16_t extra_length; +} zip_file_header_t; #if defined(ARDUINO_ARCH_ESP32) #if HASP_USE_SPIFFS > 0