mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-07-27 01:58:09 -07:00
Merge branch 'ofw_dev' into dev
This commit is contained in:
@@ -48,7 +48,6 @@ env.Append(
|
||||
File("helpers/iso14443_crc.h"),
|
||||
File("helpers/iso13239_crc.h"),
|
||||
File("helpers/nfc_data_generator.h"),
|
||||
File("helpers/nfc_dict.h"),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -1,270 +0,0 @@
|
||||
#include "nfc_dict.h"
|
||||
|
||||
#include <storage/storage.h>
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include <toolbox/stream/file_stream.h>
|
||||
#include <toolbox/stream/buffered_file_stream.h>
|
||||
#include <toolbox/args.h>
|
||||
|
||||
#include <nfc/helpers/nfc_util.h>
|
||||
|
||||
#define TAG "NfcDict"
|
||||
|
||||
struct NfcDict {
|
||||
Stream* stream;
|
||||
size_t key_size;
|
||||
size_t key_size_symbols;
|
||||
uint32_t total_keys;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
const char* path;
|
||||
FS_OpenMode open_mode;
|
||||
} NfcDictFile;
|
||||
|
||||
bool nfc_dict_check_presence(const char* path) {
|
||||
furi_assert(path);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
bool dict_present = storage_common_stat(storage, path, NULL) == FSE_OK;
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
return dict_present;
|
||||
}
|
||||
|
||||
NfcDict* nfc_dict_alloc(const char* path, NfcDictMode mode, size_t key_size) {
|
||||
furi_assert(path);
|
||||
|
||||
NfcDict* instance = malloc(sizeof(NfcDict));
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
instance->stream = buffered_file_stream_alloc(storage);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
FS_OpenMode open_mode = FSOM_OPEN_EXISTING;
|
||||
if(mode == NfcDictModeOpenAlways) {
|
||||
open_mode = FSOM_OPEN_ALWAYS;
|
||||
}
|
||||
instance->key_size = key_size;
|
||||
// Byte = 2 symbols + 1 end of line
|
||||
instance->key_size_symbols = key_size * 2 + 1;
|
||||
|
||||
bool dict_loaded = false;
|
||||
do {
|
||||
if(!buffered_file_stream_open(instance->stream, path, FSAM_READ_WRITE, open_mode)) {
|
||||
buffered_file_stream_close(instance->stream);
|
||||
break;
|
||||
}
|
||||
|
||||
// Check for new line ending
|
||||
if(!stream_eof(instance->stream)) {
|
||||
if(!stream_seek(instance->stream, -1, StreamOffsetFromEnd)) break;
|
||||
uint8_t last_char = 0;
|
||||
if(stream_read(instance->stream, &last_char, 1) != 1) break;
|
||||
if(last_char != '\n') {
|
||||
FURI_LOG_D(TAG, "Adding new line ending");
|
||||
if(stream_write_char(instance->stream, '\n') != 1) break;
|
||||
}
|
||||
if(!stream_rewind(instance->stream)) break;
|
||||
}
|
||||
|
||||
// Read total amount of keys
|
||||
FuriString* next_line;
|
||||
next_line = furi_string_alloc();
|
||||
while(true) {
|
||||
if(!stream_read_line(instance->stream, next_line)) {
|
||||
FURI_LOG_T(TAG, "No keys left in dict");
|
||||
break;
|
||||
}
|
||||
FURI_LOG_T(
|
||||
TAG,
|
||||
"Read line: %s, len: %zu",
|
||||
furi_string_get_cstr(next_line),
|
||||
furi_string_size(next_line));
|
||||
if(furi_string_get_char(next_line, 0) == '#') continue;
|
||||
if(furi_string_size(next_line) != instance->key_size_symbols) continue;
|
||||
instance->total_keys++;
|
||||
}
|
||||
furi_string_free(next_line);
|
||||
stream_rewind(instance->stream);
|
||||
|
||||
dict_loaded = true;
|
||||
FURI_LOG_I(TAG, "Loaded dictionary with %lu keys", instance->total_keys);
|
||||
} while(false);
|
||||
|
||||
if(!dict_loaded) {
|
||||
buffered_file_stream_close(instance->stream);
|
||||
free(instance);
|
||||
instance = NULL;
|
||||
}
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void nfc_dict_free(NfcDict* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->stream);
|
||||
|
||||
buffered_file_stream_close(instance->stream);
|
||||
stream_free(instance->stream);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
static void nfc_dict_int_to_str(NfcDict* instance, const uint8_t* key_int, FuriString* key_str) {
|
||||
furi_string_reset(key_str);
|
||||
for(size_t i = 0; i < instance->key_size; i++) {
|
||||
furi_string_cat_printf(key_str, "%02X", key_int[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void nfc_dict_str_to_int(NfcDict* instance, FuriString* key_str, uint64_t* key_int) {
|
||||
uint8_t key_byte_tmp;
|
||||
|
||||
*key_int = 0ULL;
|
||||
for(uint8_t i = 0; i < instance->key_size * 2; i += 2) {
|
||||
args_char_to_hex(
|
||||
furi_string_get_char(key_str, i), furi_string_get_char(key_str, i + 1), &key_byte_tmp);
|
||||
*key_int |= (uint64_t)key_byte_tmp << (8 * (instance->key_size - 1 - i / 2));
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t nfc_dict_get_total_keys(NfcDict* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
return instance->total_keys;
|
||||
}
|
||||
|
||||
bool nfc_dict_rewind(NfcDict* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->stream);
|
||||
|
||||
return stream_rewind(instance->stream);
|
||||
}
|
||||
|
||||
static bool nfc_dict_get_next_key_str(NfcDict* instance, FuriString* key) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->stream);
|
||||
|
||||
bool key_read = false;
|
||||
furi_string_reset(key);
|
||||
while(!key_read) {
|
||||
if(!stream_read_line(instance->stream, key)) break;
|
||||
if(furi_string_get_char(key, 0) == '#') continue;
|
||||
if(furi_string_size(key) != instance->key_size_symbols) continue;
|
||||
furi_string_left(key, instance->key_size_symbols - 1);
|
||||
key_read = true;
|
||||
}
|
||||
|
||||
return key_read;
|
||||
}
|
||||
|
||||
bool nfc_dict_get_next_key(NfcDict* instance, uint8_t* key, size_t key_size) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->stream);
|
||||
furi_assert(instance->key_size == key_size);
|
||||
|
||||
FuriString* temp_key = furi_string_alloc();
|
||||
uint64_t key_int = 0;
|
||||
bool key_read = nfc_dict_get_next_key_str(instance, temp_key);
|
||||
if(key_read) {
|
||||
nfc_dict_str_to_int(instance, temp_key, &key_int);
|
||||
nfc_util_num2bytes(key_int, key_size, key);
|
||||
}
|
||||
furi_string_free(temp_key);
|
||||
return key_read;
|
||||
}
|
||||
|
||||
static bool nfc_dict_is_key_present_str(NfcDict* instance, FuriString* key) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->stream);
|
||||
|
||||
FuriString* next_line;
|
||||
next_line = furi_string_alloc();
|
||||
|
||||
bool key_found = false;
|
||||
stream_rewind(instance->stream);
|
||||
while(!key_found) { //-V654
|
||||
if(!stream_read_line(instance->stream, next_line)) break;
|
||||
if(furi_string_get_char(next_line, 0) == '#') continue;
|
||||
if(furi_string_size(next_line) != instance->key_size_symbols) continue;
|
||||
furi_string_left(next_line, instance->key_size_symbols - 1);
|
||||
if(!furi_string_equal(key, next_line)) continue;
|
||||
key_found = true;
|
||||
}
|
||||
|
||||
furi_string_free(next_line);
|
||||
return key_found;
|
||||
}
|
||||
|
||||
bool nfc_dict_is_key_present(NfcDict* instance, const uint8_t* key, size_t key_size) {
|
||||
furi_assert(instance);
|
||||
furi_assert(key);
|
||||
furi_assert(instance->stream);
|
||||
furi_assert(instance->key_size == key_size);
|
||||
|
||||
FuriString* temp_key = furi_string_alloc();
|
||||
nfc_dict_int_to_str(instance, key, temp_key);
|
||||
bool key_found = nfc_dict_is_key_present_str(instance, temp_key);
|
||||
furi_string_free(temp_key);
|
||||
|
||||
return key_found;
|
||||
}
|
||||
|
||||
static bool nfc_dict_add_key_str(NfcDict* instance, FuriString* key) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->stream);
|
||||
|
||||
furi_string_cat_printf(key, "\n");
|
||||
|
||||
bool key_added = false;
|
||||
do {
|
||||
if(!stream_seek(instance->stream, 0, StreamOffsetFromEnd)) break;
|
||||
if(!stream_insert_string(instance->stream, key)) break;
|
||||
instance->total_keys++;
|
||||
key_added = true;
|
||||
} while(false);
|
||||
|
||||
furi_string_left(key, instance->key_size_symbols - 1);
|
||||
return key_added;
|
||||
}
|
||||
|
||||
bool nfc_dict_add_key(NfcDict* instance, const uint8_t* key, size_t key_size) {
|
||||
furi_assert(instance);
|
||||
furi_assert(key);
|
||||
furi_assert(instance->stream);
|
||||
furi_assert(instance->key_size == key_size);
|
||||
|
||||
FuriString* temp_key = furi_string_alloc();
|
||||
nfc_dict_int_to_str(instance, key, temp_key);
|
||||
bool key_added = nfc_dict_add_key_str(instance, temp_key);
|
||||
furi_string_free(temp_key);
|
||||
|
||||
return key_added;
|
||||
}
|
||||
|
||||
bool nfc_dict_delete_key(NfcDict* instance, const uint8_t* key, size_t key_size) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->stream);
|
||||
furi_assert(key);
|
||||
furi_assert(instance->key_size == key_size);
|
||||
|
||||
bool key_removed = false;
|
||||
uint8_t* temp_key = malloc(key_size);
|
||||
|
||||
nfc_dict_rewind(instance);
|
||||
while(!key_removed) {
|
||||
if(!nfc_dict_get_next_key(instance, temp_key, key_size)) break;
|
||||
if(memcmp(temp_key, key, key_size) == 0) {
|
||||
int32_t offset = (-1) * (instance->key_size_symbols);
|
||||
stream_seek(instance->stream, offset, StreamOffsetFromCurrent);
|
||||
if(!stream_delete(instance->stream, instance->key_size_symbols)) break;
|
||||
instance->total_keys--;
|
||||
key_removed = true;
|
||||
}
|
||||
}
|
||||
nfc_dict_rewind(instance);
|
||||
free(temp_key);
|
||||
|
||||
return key_removed;
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
NfcDictModeOpenExisting,
|
||||
NfcDictModeOpenAlways,
|
||||
} NfcDictMode;
|
||||
|
||||
typedef struct NfcDict NfcDict;
|
||||
|
||||
/** Check dictionary presence
|
||||
*
|
||||
* @param path - dictionary path
|
||||
*
|
||||
* @return true if dictionary exists, false otherwise
|
||||
*/
|
||||
bool nfc_dict_check_presence(const char* path);
|
||||
|
||||
/** Open or create dictionary
|
||||
* Depending on mode, dictionary will be opened or created.
|
||||
*
|
||||
* @param path - dictionary path
|
||||
* @param mode - NfcDictMode value
|
||||
* @param key_size - size of dictionary keys in bytes
|
||||
*
|
||||
* @return NfcDict dictionary instance
|
||||
*/
|
||||
NfcDict* nfc_dict_alloc(const char* path, NfcDictMode mode, size_t key_size);
|
||||
|
||||
/** Close dictionary
|
||||
*
|
||||
* @param instance - NfcDict dictionary instance
|
||||
*/
|
||||
void nfc_dict_free(NfcDict* instance);
|
||||
|
||||
/** Get total number of keys in dictionary
|
||||
*
|
||||
* @param instance - NfcDict dictionary instance
|
||||
*
|
||||
* @return total number of keys in dictionary
|
||||
*/
|
||||
uint32_t nfc_dict_get_total_keys(NfcDict* instance);
|
||||
|
||||
/** Rewind dictionary
|
||||
*
|
||||
* @param instance - NfcDict dictionary instance
|
||||
*
|
||||
* @return true if rewind was successful, false otherwise
|
||||
*/
|
||||
bool nfc_dict_rewind(NfcDict* instance);
|
||||
|
||||
/** Check if key is present in dictionary
|
||||
*
|
||||
* @param instance - NfcDict dictionary instance
|
||||
* @param key - key to check
|
||||
* @param key_size - size of key in bytes
|
||||
*
|
||||
* @return true if key is present, false otherwise
|
||||
*/
|
||||
bool nfc_dict_is_key_present(NfcDict* instance, const uint8_t* key, size_t key_size);
|
||||
|
||||
/** Get next key from dictionary
|
||||
* This function will return next key from dictionary. If there are no more
|
||||
* keys, it will return false, and nfc_dict_rewind() should be called.
|
||||
*
|
||||
* @param instance - NfcDict dictionary instance
|
||||
* @param key - buffer to store key
|
||||
* @param key_size - size of key in bytes
|
||||
*
|
||||
* @return true if key was successfully retrieved, false otherwise
|
||||
*/
|
||||
bool nfc_dict_get_next_key(NfcDict* instance, uint8_t* key, size_t key_size);
|
||||
|
||||
/** Add key to dictionary
|
||||
*
|
||||
* @param instance - NfcDict dictionary instance
|
||||
* @param key - key to add
|
||||
* @param key_size - size of key in bytes
|
||||
*
|
||||
* @return true if key was successfully added, false otherwise
|
||||
*/
|
||||
bool nfc_dict_add_key(NfcDict* instance, const uint8_t* key, size_t key_size);
|
||||
|
||||
/** Delete key from dictionary
|
||||
*
|
||||
* @param instance - NfcDict dictionary instance
|
||||
* @param key - key to delete
|
||||
* @param key_size - size of key in bytes
|
||||
*
|
||||
* @return true if key was successfully deleted, false otherwise
|
||||
*/
|
||||
bool nfc_dict_delete_key(NfcDict* instance, const uint8_t* key, size_t key_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -34,6 +34,7 @@ env.Append(
|
||||
File("hex.h"),
|
||||
File("simple_array.h"),
|
||||
File("bit_buffer.h"),
|
||||
File("keys_dict.h"),
|
||||
],
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,335 @@
|
||||
#include "keys_dict.h"
|
||||
|
||||
#include <storage/storage.h>
|
||||
#include <flipper_format/flipper_format.h>
|
||||
#include <toolbox/stream/file_stream.h>
|
||||
#include <toolbox/stream/buffered_file_stream.h>
|
||||
#include <toolbox/args.h>
|
||||
|
||||
#define TAG "KeysDict"
|
||||
|
||||
struct KeysDict {
|
||||
Stream* stream;
|
||||
size_t key_size;
|
||||
size_t key_size_symbols;
|
||||
size_t total_keys;
|
||||
};
|
||||
|
||||
static inline void keys_dict_add_ending_new_line(KeysDict* instance) {
|
||||
if(stream_seek(instance->stream, -1, StreamOffsetFromEnd)) {
|
||||
uint8_t last_char = 0;
|
||||
|
||||
// Check if the last char is new line or add a new line
|
||||
if(stream_read(instance->stream, &last_char, 1) == 1 && last_char != '\n') {
|
||||
FURI_LOG_D(TAG, "Adding new line ending");
|
||||
stream_write_char(instance->stream, '\n');
|
||||
}
|
||||
|
||||
stream_rewind(instance->stream);
|
||||
}
|
||||
}
|
||||
|
||||
static bool keys_dict_read_key_line(KeysDict* instance, FuriString* line, bool* is_endfile) {
|
||||
if(stream_read_line(instance->stream, line) == false) {
|
||||
*is_endfile = true;
|
||||
}
|
||||
|
||||
else {
|
||||
FURI_LOG_T(
|
||||
TAG, "Read line: %s, len: %zu", furi_string_get_cstr(line), furi_string_size(line));
|
||||
|
||||
bool is_comment = furi_string_get_char(line, 0) == '#';
|
||||
|
||||
if(!is_comment) {
|
||||
furi_string_left(line, instance->key_size_symbols - 1);
|
||||
}
|
||||
|
||||
bool is_correct_size = furi_string_size(line) == instance->key_size_symbols - 1;
|
||||
|
||||
return !is_comment && is_correct_size;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool keys_dict_check_presence(const char* path) {
|
||||
furi_assert(path);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
|
||||
bool dict_present = storage_common_stat(storage, path, NULL) == FSE_OK;
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
return dict_present;
|
||||
}
|
||||
|
||||
KeysDict* keys_dict_alloc(const char* path, KeysDictMode mode, size_t key_size) {
|
||||
furi_assert(path);
|
||||
furi_assert(key_size > 0);
|
||||
|
||||
KeysDict* instance = malloc(sizeof(KeysDict));
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
furi_assert(storage);
|
||||
|
||||
instance->stream = buffered_file_stream_alloc(storage);
|
||||
furi_assert(instance->stream);
|
||||
|
||||
FS_OpenMode open_mode = (mode == KeysDictModeOpenAlways) ? FSOM_OPEN_ALWAYS :
|
||||
FSOM_OPEN_EXISTING;
|
||||
|
||||
// Byte = 2 symbols + 1 end of line
|
||||
instance->key_size = key_size;
|
||||
instance->key_size_symbols = key_size * 2 + 1;
|
||||
|
||||
instance->total_keys = 0;
|
||||
|
||||
bool file_exists =
|
||||
buffered_file_stream_open(instance->stream, path, FSAM_READ_WRITE, open_mode);
|
||||
|
||||
if(!file_exists) {
|
||||
buffered_file_stream_close(instance->stream);
|
||||
} else {
|
||||
// Eventually add new line character in the last line to avoid skipping keys
|
||||
keys_dict_add_ending_new_line(instance);
|
||||
}
|
||||
|
||||
FuriString* line = furi_string_alloc();
|
||||
|
||||
bool is_endfile = false;
|
||||
|
||||
// In this loop we only count the entries in the file
|
||||
// We prefer not to load the whole file in memory for space reasons
|
||||
while(file_exists && !is_endfile) {
|
||||
bool read_key = keys_dict_read_key_line(instance, line, &is_endfile);
|
||||
if(read_key) {
|
||||
instance->total_keys++;
|
||||
}
|
||||
}
|
||||
stream_rewind(instance->stream);
|
||||
FURI_LOG_I(TAG, "Loaded dictionary with %u keys", instance->total_keys);
|
||||
|
||||
furi_string_free(line);
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
void keys_dict_free(KeysDict* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->stream);
|
||||
|
||||
buffered_file_stream_close(instance->stream);
|
||||
stream_free(instance->stream);
|
||||
free(instance);
|
||||
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
}
|
||||
|
||||
static void keys_dict_int_to_str(KeysDict* instance, const uint8_t* key_int, FuriString* key_str) {
|
||||
furi_assert(instance);
|
||||
furi_assert(key_str);
|
||||
furi_assert(key_int);
|
||||
|
||||
furi_string_reset(key_str);
|
||||
|
||||
for(size_t i = 0; i < instance->key_size; i++)
|
||||
furi_string_cat_printf(key_str, "%02X", key_int[i]);
|
||||
}
|
||||
|
||||
static void keys_dict_str_to_int(KeysDict* instance, FuriString* key_str, uint64_t* key_int) {
|
||||
furi_assert(instance);
|
||||
furi_assert(key_str);
|
||||
furi_assert(key_int);
|
||||
|
||||
uint8_t key_byte_tmp;
|
||||
char h, l;
|
||||
|
||||
*key_int = 0ULL;
|
||||
|
||||
for(size_t i = 0; i < instance->key_size_symbols - 1; i += 2) {
|
||||
h = furi_string_get_char(key_str, i);
|
||||
l = furi_string_get_char(key_str, i + 1);
|
||||
|
||||
args_char_to_hex(h, l, &key_byte_tmp);
|
||||
*key_int |= (uint64_t)key_byte_tmp << (8 * (instance->key_size - 1 - i / 2));
|
||||
}
|
||||
}
|
||||
|
||||
size_t keys_dict_get_total_keys(KeysDict* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
return instance->total_keys;
|
||||
}
|
||||
|
||||
bool keys_dict_rewind(KeysDict* instance) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->stream);
|
||||
|
||||
return stream_rewind(instance->stream);
|
||||
}
|
||||
|
||||
static bool keys_dict_get_next_key_str(KeysDict* instance, FuriString* key) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->stream);
|
||||
furi_assert(key);
|
||||
|
||||
bool key_read = false;
|
||||
bool is_endfile = false;
|
||||
|
||||
furi_string_reset(key);
|
||||
|
||||
while(!key_read && !is_endfile) key_read = keys_dict_read_key_line(instance, key, &is_endfile);
|
||||
|
||||
return key_read;
|
||||
}
|
||||
|
||||
bool keys_dict_get_next_key(KeysDict* instance, uint8_t* key, size_t key_size) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->stream);
|
||||
furi_assert(instance->key_size == key_size);
|
||||
furi_assert(key);
|
||||
|
||||
FuriString* temp_key = furi_string_alloc();
|
||||
|
||||
bool key_read = keys_dict_get_next_key_str(instance, temp_key);
|
||||
|
||||
if(key_read) {
|
||||
size_t tmp_len = key_size;
|
||||
uint64_t key_int = 0;
|
||||
|
||||
keys_dict_str_to_int(instance, temp_key, &key_int);
|
||||
|
||||
while(tmp_len--) {
|
||||
key[tmp_len] = (uint8_t)key_int;
|
||||
key_int >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
furi_string_free(temp_key);
|
||||
return key_read;
|
||||
}
|
||||
|
||||
static bool keys_dict_is_key_present_str(KeysDict* instance, FuriString* key) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->stream);
|
||||
furi_assert(key);
|
||||
|
||||
FuriString* line = furi_string_alloc();
|
||||
|
||||
bool is_endfile = false;
|
||||
bool line_found = false;
|
||||
|
||||
uint32_t actual_pos = stream_tell(instance->stream);
|
||||
stream_rewind(instance->stream);
|
||||
|
||||
while(!line_found && !is_endfile)
|
||||
line_found = // The line is found if the line was read and the key is equal to the line
|
||||
(keys_dict_read_key_line(instance, line, &is_endfile)) &&
|
||||
(furi_string_equal(key, line));
|
||||
|
||||
furi_string_free(line);
|
||||
|
||||
// Restore the position of the stream
|
||||
stream_seek(instance->stream, actual_pos, StreamOffsetFromStart);
|
||||
|
||||
return line_found;
|
||||
}
|
||||
|
||||
bool keys_dict_is_key_present(KeysDict* instance, const uint8_t* key, size_t key_size) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->stream);
|
||||
furi_assert(instance->key_size == key_size);
|
||||
furi_assert(key);
|
||||
|
||||
FuriString* temp_key = furi_string_alloc();
|
||||
|
||||
keys_dict_int_to_str(instance, key, temp_key);
|
||||
bool key_found = keys_dict_is_key_present_str(instance, temp_key);
|
||||
furi_string_free(temp_key);
|
||||
|
||||
return key_found;
|
||||
}
|
||||
|
||||
static bool keys_dict_add_key_str(KeysDict* instance, FuriString* key) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->stream);
|
||||
furi_assert(key);
|
||||
|
||||
furi_string_cat_str(key, "\n");
|
||||
|
||||
bool key_added = false;
|
||||
|
||||
uint32_t actual_pos = stream_tell(instance->stream);
|
||||
|
||||
if(stream_seek(instance->stream, 0, StreamOffsetFromEnd) &&
|
||||
stream_insert_string(instance->stream, key)) {
|
||||
instance->total_keys++;
|
||||
key_added = true;
|
||||
}
|
||||
|
||||
stream_seek(instance->stream, actual_pos, StreamOffsetFromStart);
|
||||
|
||||
return key_added;
|
||||
}
|
||||
|
||||
bool keys_dict_add_key(KeysDict* instance, const uint8_t* key, size_t key_size) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->stream);
|
||||
furi_assert(instance->key_size == key_size);
|
||||
furi_assert(key);
|
||||
|
||||
FuriString* temp_key = furi_string_alloc();
|
||||
furi_assert(temp_key);
|
||||
|
||||
keys_dict_int_to_str(instance, key, temp_key);
|
||||
bool key_added = keys_dict_add_key_str(instance, temp_key);
|
||||
|
||||
FURI_LOG_I(TAG, "Added key %s", furi_string_get_cstr(temp_key));
|
||||
|
||||
furi_string_free(temp_key);
|
||||
|
||||
return key_added;
|
||||
}
|
||||
|
||||
bool keys_dict_delete_key(KeysDict* instance, const uint8_t* key, size_t key_size) {
|
||||
furi_assert(instance);
|
||||
furi_assert(instance->stream);
|
||||
furi_assert(instance->key_size == key_size);
|
||||
furi_assert(key);
|
||||
|
||||
bool key_removed = false;
|
||||
bool is_endfile = false;
|
||||
|
||||
uint8_t* temp_key = malloc(key_size);
|
||||
|
||||
stream_rewind(instance->stream);
|
||||
|
||||
while(!key_removed && !is_endfile) {
|
||||
if(!keys_dict_get_next_key(instance, temp_key, key_size)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(memcmp(temp_key, key, key_size) == 0) {
|
||||
stream_seek(instance->stream, -instance->key_size_symbols, StreamOffsetFromCurrent);
|
||||
if(stream_delete(instance->stream, instance->key_size_symbols) == false) {
|
||||
break;
|
||||
}
|
||||
instance->total_keys--;
|
||||
key_removed = true;
|
||||
}
|
||||
}
|
||||
|
||||
FuriString* tmp = furi_string_alloc();
|
||||
|
||||
keys_dict_int_to_str(instance, key, tmp);
|
||||
|
||||
FURI_LOG_I(TAG, "Removed key %s", furi_string_get_cstr(tmp));
|
||||
|
||||
furi_string_free(tmp);
|
||||
|
||||
stream_rewind(instance->stream);
|
||||
free(temp_key);
|
||||
|
||||
return key_removed;
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum {
|
||||
KeysDictModeOpenExisting,
|
||||
KeysDictModeOpenAlways,
|
||||
} KeysDictMode;
|
||||
|
||||
typedef struct KeysDict KeysDict;
|
||||
|
||||
/** Check if the file list exists
|
||||
*
|
||||
* @param path - list path
|
||||
*
|
||||
* @return true if list exists, false otherwise
|
||||
*/
|
||||
bool keys_dict_check_presence(const char* path);
|
||||
|
||||
/** Open or create list
|
||||
* Depending on mode, list will be opened or created.
|
||||
*
|
||||
* @param path - Path of the file that contain the list
|
||||
* @param mode - ListKeysMode value
|
||||
* @param key_size - Size of each key in bytes
|
||||
*
|
||||
* @return Returns KeysDict list instance
|
||||
*/
|
||||
KeysDict* keys_dict_alloc(const char* path, KeysDictMode mode, size_t key_size);
|
||||
|
||||
/** Close list
|
||||
*
|
||||
* @param instance - KeysDict list instance
|
||||
*/
|
||||
void keys_dict_free(KeysDict* instance);
|
||||
|
||||
/** Get total number of keys in list
|
||||
*
|
||||
* @param instance - KeysDict list instance
|
||||
*
|
||||
* @return Returns total number of keys in list
|
||||
*/
|
||||
size_t keys_dict_get_total_keys(KeysDict* instance);
|
||||
|
||||
/** Rewind list
|
||||
*
|
||||
* @param instance - KeysDict list instance
|
||||
*
|
||||
* @return Returns true if rewind was successful, false otherwise
|
||||
*/
|
||||
bool keys_dict_rewind(KeysDict* instance);
|
||||
|
||||
/** Check if key is present in list
|
||||
*
|
||||
* @param instance - KeysDict list instance
|
||||
* @param key - key to check
|
||||
* @param key_size - Size of the key in bytes
|
||||
*
|
||||
* @return Returns true if key is present, false otherwise
|
||||
*/
|
||||
bool keys_dict_is_key_present(KeysDict* instance, const uint8_t* key, size_t key_size);
|
||||
|
||||
/** Get next key from the list
|
||||
* This function will return next key from list. If there are no more
|
||||
* keys, it will return false, and keys_dict_rewind() should be called.
|
||||
*
|
||||
* @param instance - KeysDict list instance
|
||||
* @param key - Array where to store key
|
||||
* @param key_size - Size of key in bytes
|
||||
*
|
||||
* @return Returns true if key was successfully retrieved, false otherwise
|
||||
*/
|
||||
bool keys_dict_get_next_key(KeysDict* instance, uint8_t* key, size_t key_size);
|
||||
|
||||
/** Add key to list
|
||||
*
|
||||
* @param instance - KeysDict list instance
|
||||
* @param key - Key to add
|
||||
* @param key_size - Size of the key in bytes
|
||||
*
|
||||
* @return Returns true if key was successfully added, false otherwise
|
||||
*/
|
||||
bool keys_dict_add_key(KeysDict* instance, const uint8_t* key, size_t key_size);
|
||||
|
||||
/** Delete key from list
|
||||
*
|
||||
* @param instance - KeysDict list instance
|
||||
* @param key - Key to delete
|
||||
* @param key_size - Size of the key in bytes
|
||||
*
|
||||
* @return Returns true if key was successfully deleted, false otherwise
|
||||
*/
|
||||
bool keys_dict_delete_key(KeysDict* instance, const uint8_t* key, size_t key_size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user