diff --git a/client/fileutils.c b/client/fileutils.c
new file mode 100644
index 000000000..b89925334
--- /dev/null
+++ b/client/fileutils.c
@@ -0,0 +1,618 @@
+/*****************************************************************************
+ * WARNING
+ *
+ * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
+ *
+ * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
+ * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
+ * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
+ *
+ * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
+ *
+ *****************************************************************************
+ *
+ * This file is part of loclass. It is a reconstructon of the cipher engine
+ * used in iClass, and RFID techology.
+ *
+ * The implementation is based on the work performed by
+ * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
+ * Milosch Meriac in the paper "Dismantling IClass".
+ *
+ * Copyright (C) 2014 Martin Holst Swende
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, or, at your option, any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with loclass. If not, see .
+ *
+ *
+ ****************************************************************************/
+#include "fileutils.h"
+
+#include
+
+#include "pm3_cmd.h"
+#include "commonutil.h"
+#include "util.h"
+
+
+#ifndef ON_DEVICE
+
+#define PATH_MAX_LENGTH 100
+
+/**
+ * @brief checks if a file exists
+ * @param filename
+ * @return
+ */
+int fileExists(const char *filename) {
+
+#ifdef _WIN32
+ struct _stat st;
+ int result = _stat(filename, &st);
+#else
+ struct stat st;
+ int result = stat(filename, &st);
+#endif
+ return result == 0;
+}
+
+static char *filenamemcopy(const char *preferredName, const char *suffix) {
+ if (preferredName == NULL) return NULL;
+ if (suffix == NULL) return NULL;
+ char *fileName = (char *) calloc(strlen(preferredName) + strlen(suffix) + 1, sizeof(uint8_t));
+ if (fileName == NULL)
+ return NULL;
+ strcpy(fileName, preferredName);
+ if (str_endswith(fileName, suffix))
+ return fileName;
+ strcat(fileName, suffix);
+ return fileName;
+}
+
+static char *newfilenamemcopy(const char *preferredName, const char *suffix) {
+ if (preferredName == NULL) return NULL;
+ if (suffix == NULL) return NULL;
+ uint16_t preferredNameLen = strlen(preferredName);
+ if (str_endswith(preferredName, suffix))
+ preferredNameLen -= strlen(suffix);
+ char *fileName = (char *) calloc(preferredNameLen + strlen(suffix) + 1 + 10, sizeof(uint8_t)); // 10: room for filenum to ensure new filename
+ if (fileName == NULL) {
+ return NULL;
+ }
+ int num = 1;
+ sprintf(fileName, "%.*s%s", preferredNameLen, preferredName, suffix);
+ while (fileExists(fileName)) {
+ sprintf(fileName, "%.*s-%d%s", preferredNameLen, preferredName, num, suffix);
+ num++;
+ }
+ return fileName;
+}
+
+int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen) {
+
+ if (data == NULL) return 1;
+ char *fileName = newfilenamemcopy(preferredName, suffix);
+ if (fileName == NULL) return 1;
+
+ /* We should have a valid filename now, e.g. dumpdata-3.bin */
+
+ /*Opening file for writing in binary mode*/
+ FILE *f = fopen(fileName, "wb");
+ if (!f) {
+ PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", fileName);
+ free(fileName);
+ return PM3_EFILE;
+ }
+ fwrite(data, 1, datalen, f);
+ fflush(f);
+ fclose(f);
+ PrintAndLogEx(SUCCESS, "saved %u bytes to binary file " _YELLOW_("%s"), datalen, fileName);
+ free(fileName);
+ return PM3_SUCCESS;
+}
+
+int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t blocksize) {
+
+ if (data == NULL) return 1;
+ char *fileName = newfilenamemcopy(preferredName, ".eml");
+ if (fileName == NULL) return 1;
+
+ int retval = PM3_SUCCESS;
+ int blocks = datalen / blocksize;
+ uint16_t currblock = 1;
+
+ /* We should have a valid filename now, e.g. dumpdata-3.bin */
+
+ /*Opening file for writing in text mode*/
+ FILE *f = fopen(fileName, "w+");
+ if (!f) {
+ PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", fileName);
+ retval = PM3_EFILE;
+ goto out;
+ }
+
+ for (size_t i = 0; i < datalen; i++) {
+ fprintf(f, "%02X", data[i]);
+
+ // no extra line in the end
+ if ((i + 1) % blocksize == 0 && currblock != blocks) {
+ fprintf(f, "\n");
+ currblock++;
+ }
+ }
+ // left overs
+ if (datalen % blocksize != 0) {
+ int index = blocks * blocksize;
+ for (size_t j = 0; j < datalen % blocksize; j++) {
+ fprintf(f, "%02X", data[index + j]);
+ }
+ }
+ fflush(f);
+ fclose(f);
+ PrintAndLogEx(SUCCESS, "saved %d blocks to text file " _YELLOW_("%s"), blocks, fileName);
+
+out:
+ free(fileName);
+ return retval;
+}
+
+int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen) {
+
+ if (data == NULL) return 1;
+ char *fileName = newfilenamemcopy(preferredName, ".json");
+ if (fileName == NULL) return 1;
+
+ int retval = PM3_SUCCESS;
+
+ json_t *root = json_object();
+ JsonSaveStr(root, "Created", "proxmark3");
+ switch (ftype) {
+ case jsfRaw: {
+ JsonSaveStr(root, "FileType", "raw");
+ JsonSaveBufAsHexCompact(root, "raw", data, datalen);
+ break;
+ }
+ case jsfCardMemory: {
+ JsonSaveStr(root, "FileType", "mfcard");
+ for (size_t i = 0; i < (datalen / 16); i++) {
+ char path[PATH_MAX_LENGTH] = {0};
+ sprintf(path, "$.blocks.%zu", i);
+ JsonSaveBufAsHexCompact(root, path, &data[i * 16], 16);
+
+ if (i == 0) {
+ JsonSaveBufAsHexCompact(root, "$.Card.UID", &data[0], 4);
+ JsonSaveBufAsHexCompact(root, "$.Card.SAK", &data[5], 1);
+ JsonSaveBufAsHexCompact(root, "$.Card.ATQA", &data[6], 2);
+ }
+
+ if (mfIsSectorTrailer(i)) {
+ memset(path, 0x00, sizeof(path));
+ sprintf(path, "$.SectorKeys.%d.KeyA", mfSectorNum(i));
+ JsonSaveBufAsHexCompact(root, path, &data[i * 16], 6);
+
+ memset(path, 0x00, sizeof(path));
+ sprintf(path, "$.SectorKeys.%d.KeyB", mfSectorNum(i));
+ JsonSaveBufAsHexCompact(root, path, &data[i * 16 + 10], 6);
+
+ memset(path, 0x00, sizeof(path));
+ uint8_t *adata = &data[i * 16 + 6];
+ sprintf(path, "$.SectorKeys.%d.AccessConditions", mfSectorNum(i));
+ JsonSaveBufAsHexCompact(root, path, &data[i * 16 + 6], 4);
+
+ memset(path, 0x00, sizeof(path));
+ sprintf(path, "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i), i - 3);
+ JsonSaveStr(root, path, mfGetAccessConditionsDesc(0, adata));
+
+ memset(path, 0x00, sizeof(path));
+ sprintf(path, "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i), i - 2);
+ JsonSaveStr(root, path, mfGetAccessConditionsDesc(1, adata));
+
+ memset(path, 0x00, sizeof(path));
+ sprintf(path, "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i), i - 1);
+ JsonSaveStr(root, path, mfGetAccessConditionsDesc(2, adata));
+
+ memset(path, 0x00, sizeof(path));
+ sprintf(path, "$.SectorKeys.%d.AccessConditionsText.block%zu", mfSectorNum(i), i);
+ JsonSaveStr(root, path, mfGetAccessConditionsDesc(3, adata));
+
+ memset(path, 0x00, sizeof(path));
+ sprintf(path, "$.SectorKeys.%d.AccessConditionsText.UserData", mfSectorNum(i));
+ JsonSaveBufAsHexCompact(root, path, &adata[3], 1);
+ }
+ }
+ break;
+ }
+ case jsfMfuMemory: {
+ JsonSaveStr(root, "FileType", "mfu");
+
+ mfu_dump_t *tmp = (mfu_dump_t *)data;
+
+ uint8_t uid[7] = {0};
+ memcpy(uid, tmp->data, 3);
+ memcpy(uid + 3, tmp->data + 4, 4);
+
+ char path[PATH_MAX_LENGTH] = {0};
+
+ JsonSaveBufAsHexCompact(root, "$.Card.UID", uid, sizeof(uid));
+ JsonSaveBufAsHexCompact(root, "$.Card.Version", tmp->version, sizeof(tmp->version));
+ JsonSaveBufAsHexCompact(root, "$.Card.TBO_0", tmp->tbo, sizeof(tmp->tbo));
+ JsonSaveBufAsHexCompact(root, "$.Card.TBO_1", tmp->tbo1, sizeof(tmp->tbo1));
+ JsonSaveBufAsHexCompact(root, "$.Card.Signature", tmp->signature, sizeof(tmp->signature));
+ for (uint8_t i = 0; i < 3; i ++) {
+ sprintf(path, "$.Card.Counter%d", i);
+ JsonSaveBufAsHexCompact(root, path, tmp->counter_tearing[i], 3);
+ sprintf(path, "$.Card.Tearing%d", i);
+ JsonSaveBufAsHexCompact(root, path, tmp->counter_tearing[i] + 3, 1);
+ }
+
+ // size of header 56b
+ size_t len = (datalen - MFU_DUMP_PREFIX_LENGTH) / 4;
+
+ for (size_t i = 0; i < len; i++) {
+ sprintf(path, "$.blocks.%zu", i);
+ JsonSaveBufAsHexCompact(root, path, tmp->data + (i * 4), 4);
+ }
+ break;
+ }
+ case jsfHitag: {
+ JsonSaveStr(root, "FileType", "hitag");
+ uint8_t uid[4] = {0};
+ memcpy(uid, data, 4);
+
+ JsonSaveBufAsHexCompact(root, "$.Card.UID", uid, sizeof(uid));
+
+ for (size_t i = 0; i < (datalen / 4); i++) {
+ char path[PATH_MAX_LENGTH] = {0};
+ sprintf(path, "$.blocks.%zu", i);
+ JsonSaveBufAsHexCompact(root, path, data + (i * 4), 4);
+ }
+ break;
+ }
+ }
+
+ int res = json_dump_file(root, fileName, JSON_INDENT(2));
+ if (res) {
+ PrintAndLogEx(FAILED, "error: can't save the file: " _YELLOW_("%s"), fileName);
+ json_decref(root);
+ retval = 200;
+ goto out;
+ }
+ PrintAndLogEx(SUCCESS, "saved to json file " _YELLOW_("%s"), fileName);
+ json_decref(root);
+
+out:
+ free(fileName);
+ return retval;
+}
+
+int loadFile(const char *preferredName, const char *suffix, void *data, size_t maxdatalen, size_t *datalen) {
+
+ if (data == NULL) return 1;
+ char *fileName = filenamemcopy(preferredName, suffix);
+ if (fileName == NULL) return 1;
+
+ int retval = PM3_SUCCESS;
+
+ FILE *f = fopen(fileName, "rb");
+ if (!f) {
+ PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", fileName);
+ free(fileName);
+ return PM3_EFILE;
+ }
+
+ // get filesize in order to malloc memory
+ fseek(f, 0, SEEK_END);
+ long fsize = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ if (fsize <= 0) {
+ PrintAndLogEx(FAILED, "error, when getting filesize");
+ retval = 1;
+ goto out;
+ }
+
+ uint8_t *dump = calloc(fsize, sizeof(uint8_t));
+ if (!dump) {
+ PrintAndLogEx(FAILED, "error, cannot allocate memory");
+ retval = 2;
+ goto out;
+ }
+
+ size_t bytes_read = fread(dump, 1, fsize, f);
+
+ if (bytes_read != fsize) {
+ PrintAndLogEx(FAILED, "error, bytes read mismatch file size");
+ free(dump);
+ retval = 3;
+ goto out;
+ }
+
+ if (bytes_read > maxdatalen) {
+ PrintAndLogEx(WARNING, "Warning, bytes read exceed calling array limit. Max bytes is %d bytes", maxdatalen);
+ bytes_read = maxdatalen;
+ }
+
+ memcpy((data), dump, bytes_read);
+ free(dump);
+
+ PrintAndLogEx(SUCCESS, "loaded %d bytes from binary file " _YELLOW_("%s"), bytes_read, fileName);
+
+ *datalen = bytes_read;
+
+out:
+ fclose(f);
+ free(fileName);
+
+ return retval;
+}
+
+int loadFileEML(const char *preferredName, void *data, size_t *datalen) {
+
+ if (data == NULL) return 1;
+ char *fileName = filenamemcopy(preferredName, ".eml");
+ if (fileName == NULL) return 1;
+
+ size_t counter = 0;
+ int retval = PM3_SUCCESS, hexlen = 0;
+
+ FILE *f = fopen(fileName, "r");
+ if (!f) {
+ PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", fileName);
+ retval = PM3_EFILE;
+ goto out;
+ }
+
+ // 128 + 2 newline chars + 1 null terminator
+ char line[131];
+ memset(line, 0, sizeof(line));
+ uint8_t buf[64] = {0x00};
+
+ while (!feof(f)) {
+
+ memset(line, 0, sizeof(line));
+
+ if (fgets(line, sizeof(line), f) == NULL) {
+ if (feof(f))
+ break;
+ fclose(f);
+ PrintAndLogEx(FAILED, "File reading error.");
+ retval = 2;
+ goto out;
+ }
+
+ if (line[0] == '#')
+ continue;
+
+ int res = param_gethex_to_eol(line, 0, buf, sizeof(buf), &hexlen);
+ if (res == 0 || res == 1) {
+ memcpy(data + counter, buf, hexlen);
+ counter += hexlen;
+ }
+ }
+ fclose(f);
+ PrintAndLogEx(SUCCESS, "loaded %d bytes from text file " _YELLOW_("%s"), counter, fileName);
+
+ if (datalen)
+ *datalen = counter;
+
+out:
+ free(fileName);
+ return retval;
+}
+
+int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen) {
+
+ if (data == NULL) return 1;
+ char *fileName = filenamemcopy(preferredName, ".json");
+ if (fileName == NULL) return 1;
+
+ *datalen = 0;
+ json_t *root;
+ json_error_t error;
+
+ int retval = PM3_SUCCESS;
+
+ root = json_load_file(fileName, 0, &error);
+ if (!root) {
+ PrintAndLogEx(ERR, "ERROR: json " _YELLOW_("%s") " error on line %d: %s", fileName, error.line, error.text);
+ retval = 2;
+ goto out;
+ }
+
+ if (!json_is_object(root)) {
+ PrintAndLogEx(ERR, "ERROR: Invalid json " _YELLOW_("%s") " format. root must be an object.", fileName);
+ retval = 3;
+ goto out;
+ }
+
+ uint8_t *udata = (uint8_t *)data;
+ char ctype[100] = {0};
+ JsonLoadStr(root, "$.FileType", ctype);
+
+ if (!strcmp(ctype, "raw")) {
+ JsonLoadBufAsHex(root, "$.raw", udata, maxdatalen, datalen);
+ }
+
+ if (!strcmp(ctype, "mfcard")) {
+ size_t sptr = 0;
+ for (int i = 0; i < 256; i++) {
+ if (sptr + 16 > maxdatalen) {
+ retval = 5;
+ goto out;
+ }
+
+ char path[30] = {0};
+ sprintf(path, "$.blocks.%d", i);
+
+ size_t len = 0;
+ JsonLoadBufAsHex(root, path, &udata[sptr], 16, &len);
+ if (!len)
+ break;
+
+ sptr += len;
+ }
+
+ *datalen = sptr;
+ }
+
+ if (!strcmp(ctype, "mfu")) {
+ size_t sptr = 0;
+ for (int i = 0; i < 256; i++) {
+ if (sptr + 4 > maxdatalen) {
+ retval = 5;
+ goto out;
+ }
+
+ char path[30] = {0};
+ sprintf(path, "$.blocks.%d", i);
+
+ size_t len = 0;
+ JsonLoadBufAsHex(root, path, &udata[sptr], 4, &len);
+ if (!len)
+ break;
+
+ sptr += len;
+ }
+
+ *datalen = sptr;
+ }
+
+ if (!strcmp(ctype, "hitag")) {
+ size_t sptr = 0;
+ for (size_t i = 0; i < (maxdatalen / 4); i++) {
+ if (sptr + 4 > maxdatalen) {
+ retval = 5;
+ goto out;
+ }
+
+ char path[30] = {0};
+ sprintf(path, "$.blocks.%zu", i);
+
+ size_t len = 0;
+ JsonLoadBufAsHex(root, path, &udata[sptr], 4, &len);
+ if (!len)
+ break;
+
+ sptr += len;
+ }
+
+ *datalen = sptr;
+ }
+
+ PrintAndLogEx(SUCCESS, "loaded from JSON file " _YELLOW_("%s"), fileName);
+out:
+ json_decref(root);
+ free(fileName);
+ return retval;
+}
+
+int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, uint8_t keylen, uint16_t *keycnt) {
+
+
+ if (data == NULL) return 1;
+ char *fileName = filenamemcopy(preferredName, ".dic");
+ if (fileName == NULL) return 1;
+
+ // t5577 == 4bytes
+ // mifare == 6 bytes
+ // iclass == 8 bytes
+ // default to 6 bytes.
+ if (keylen != 4 && keylen != 6 && keylen != 8) {
+ keylen = 6;
+ }
+
+ // double up since its chars
+ keylen <<= 1;
+
+ char line[255];
+
+ size_t counter = 0;
+ int retval = PM3_SUCCESS;
+
+ FILE *f = fopen(fileName, "r");
+ if (!f) {
+ PrintAndLogEx(WARNING, "file not found or locked. '" _YELLOW_("%s")"'", fileName);
+ retval = PM3_EFILE;
+ goto out;
+ }
+
+ // read file
+ while (fgets(line, sizeof(line), f)) {
+
+ // add null terminator
+ line[keylen] = 0;
+
+ // smaller keys than expected is skipped
+ if (strlen(line) < keylen)
+ continue;
+
+ // The line start with # is comment, skip
+ if (line[0] == '#')
+ continue;
+
+ if (!isxdigit(line[0])) {
+ PrintAndLogEx(FAILED, "file content error. '%s' must include " _BLUE_("%2d") "HEX symbols", line, keylen);
+ continue;
+ }
+
+ uint64_t key = strtoull(line, NULL, 16);
+
+ num_to_bytes(key, keylen >> 1, data + counter);
+ (*keycnt)++;
+ memset(line, 0, sizeof(line));
+ counter += (keylen >> 1);
+ }
+ fclose(f);
+ PrintAndLogEx(SUCCESS, "loaded " _GREEN_("%2d") "keys from dictionary file " _YELLOW_("%s"), *keycnt, fileName);
+
+ if (datalen)
+ *datalen = counter;
+out:
+ free(fileName);
+ return retval;
+}
+
+int convertOldMfuDump(uint8_t **dump, size_t *dumplen) {
+ if (!dump || !dumplen || *dumplen < OLD_MFU_DUMP_PREFIX_LENGTH)
+ return 1;
+ // try to check new file format
+ mfu_dump_t *mfu_dump = (mfu_dump_t *) *dump;
+ if ((*dumplen - MFU_DUMP_PREFIX_LENGTH) / 4 - 1 == mfu_dump->pages)
+ return 0;
+ // convert old format
+ old_mfu_dump_t *old_mfu_dump = (old_mfu_dump_t *) *dump;
+
+ size_t old_data_len = *dumplen - OLD_MFU_DUMP_PREFIX_LENGTH;
+ size_t new_dump_len = old_data_len + MFU_DUMP_PREFIX_LENGTH;
+
+ mfu_dump = (mfu_dump_t *) calloc(new_dump_len, sizeof(uint8_t));
+
+ memcpy(mfu_dump->version, old_mfu_dump->version, 8);
+ memcpy(mfu_dump->tbo, old_mfu_dump->tbo, 2);
+ mfu_dump->tbo1[0] = old_mfu_dump->tbo1[0];
+ memcpy(mfu_dump->signature, old_mfu_dump->signature, 32);
+ for (int i = 0; i < 3; i++)
+ mfu_dump->counter_tearing[i][3] = old_mfu_dump->tearing[i];
+
+ memcpy(mfu_dump->data, old_mfu_dump->data, old_data_len);
+ mfu_dump->pages = old_data_len / 4 - 1;
+ // free old buffer, return new buffer
+ *dumplen = new_dump_len;
+ free(*dump);
+ *dump = (uint8_t *) mfu_dump;
+ PrintAndLogEx(SUCCESS, "old mfu dump format, was converted on load to " _GREEN_("%d") " pages", mfu_dump->pages + 1);
+ return PM3_SUCCESS;
+}
+
+
+#else //if we're on ARM
+
+#endif
diff --git a/client/fileutils.h b/client/fileutils.h
new file mode 100644
index 000000000..74d54000b
--- /dev/null
+++ b/client/fileutils.h
@@ -0,0 +1,181 @@
+/*****************************************************************************
+ * WARNING
+ *
+ * THIS CODE IS CREATED FOR EXPERIMENTATION AND EDUCATIONAL USE ONLY.
+ *
+ * USAGE OF THIS CODE IN OTHER WAYS MAY INFRINGE UPON THE INTELLECTUAL
+ * PROPERTY OF OTHER PARTIES, SUCH AS INSIDE SECURE AND HID GLOBAL,
+ * AND MAY EXPOSE YOU TO AN INFRINGEMENT ACTION FROM THOSE PARTIES.
+ *
+ * THIS CODE SHOULD NEVER BE USED TO INFRINGE PATENTS OR INTELLECTUAL PROPERTY RIGHTS.
+ *
+ *****************************************************************************
+ *
+ * This file is part of loclass. It is a reconstructon of the cipher engine
+ * used in iClass, and RFID techology.
+ *
+ * The implementation is based on the work performed by
+ * Flavio D. Garcia, Gerhard de Koning Gans, Roel Verdult and
+ * Milosch Meriac in the paper "Dismantling IClass".
+ *
+ * Copyright (C) 2014 Martin Holst Swende
+ *
+ * This is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation, or, at your option, any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with loclass. If not, see .
+ *
+ *
+ ****************************************************************************/
+
+#ifndef FILEUTILS_H
+#define FILEUTILS_H
+
+#ifndef ON_DEVICE
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include "../ui.h"
+#include "../emv/emvjson.h"
+#include "mifare/mifare4.h"
+#include "cmdhfmfu.h"
+
+typedef enum {
+ jsfRaw,
+ jsfCardMemory,
+ jsfMfuMemory,
+ jsfHitag,
+// jsf14b,
+// jsf15,
+// jsfLegic,
+// jsfT55xx,
+} JSONFileType;
+
+int fileExists(const char *filename);
+
+/**
+ * @brief Utility function to save data to a binary file. This method takes a preferred name, but if that
+ * file already exists, it tries with another name until it finds something suitable.
+ * E.g. dumpdata-15.txt
+ *
+ * @param preferredName
+ * @param suffix the file suffix. Including the ".".
+ * @param data The binary data to write to the file
+ * @param datalen the length of the data
+ * @return 0 for ok, 1 for failz
+ */
+int saveFile(const char *preferredName, const char *suffix, const void *data, size_t datalen);
+
+/**
+ * @brief Utility function to save data to a textfile (EML). This method takes a preferred name, but if that
+ * file already exists, it tries with another name until it finds something suitable.
+ * E.g. dumpdata-15.txt
+ *
+ * @param preferredName
+ * @param data The binary data to write to the file
+ * @param datalen the length of the data
+ * @param blocksize the length of one row
+ * @return 0 for ok, 1 for failz
+*/
+int saveFileEML(const char *preferredName, uint8_t *data, size_t datalen, size_t blocksize);
+
+/** STUB
+ * @brief Utility function to save JSON data to a file. This method takes a preferred name, but if that
+ * file already exists, it tries with another name until it finds something suitable.
+ * E.g. dumpdata-15.json
+ *
+ * @param preferredName
+ * @param ftype type of file.
+ * @param data The binary data to write to the file
+ * @param datalen the length of the data
+ * @return 0 for ok, 1 for failz
+ */
+int saveFileJSON(const char *preferredName, JSONFileType ftype, uint8_t *data, size_t datalen);
+
+/** STUB
+ * @brief Utility function to load data from a binary file. This method takes a preferred name.
+ * E.g. dumpdata-15.bin
+ *
+ * @param preferredName
+ * @param suffix the file suffix. Including the ".".
+ * @param data The data array to store the loaded bytes from file
+ * @param maxdatalen the number of bytes that your data array has
+ * @param datalen the number of bytes loaded from file
+ * @return 0 for ok, 1 for failz
+*/
+int loadFile(const char *preferredName, const char *suffix, void *data, size_t maxdatalen, size_t *datalen);
+
+/**
+ * @brief Utility function to load data from a textfile (EML). This method takes a preferred name.
+ * E.g. dumpdata-15.txt
+ *
+ * @param preferredName
+ * @param data The data array to store the loaded bytes from file
+ * @param datalen the number of bytes loaded from file
+ * @return 0 for ok, 1 for failz
+*/
+int loadFileEML(const char *preferredName, void *data, size_t *datalen);
+
+/**
+ * @brief Utility function to load data from a JSON textfile. This method takes a preferred name.
+ * E.g. dumpdata-15.json
+ *
+ * @param preferredName
+ * @param data The data array to store the loaded bytes from file
+ * @param maxdatalen maximum size of data array in bytes
+ * @param datalen the number of bytes loaded from file
+ * @return 0 for ok, 1 for failz
+*/
+int loadFileJSON(const char *preferredName, void *data, size_t maxdatalen, size_t *datalen);
+
+
+/**
+ * @brief Utility function to load data from a DICTIONARY textfile. This method takes a preferred name.
+ * E.g. default_keys.dic
+ *
+ * @param preferredName
+ * @param data The data array to store the loaded bytes from file
+ * @param maxdatalen maximum size of data array in bytes
+ * @param datalen the number of bytes loaded from file
+ * @param keylen the number of bytes a key per row is
+ * @return 0 for ok, 1 for failz
+*/
+int loadFileDICTIONARY(const char *preferredName, void *data, size_t *datalen, uint8_t keylen, uint16_t *keycnt);
+
+/**
+ * @brief Utility function to check and convert old mfu dump format to new
+ *
+ * @param dump pointer to loaded dump to check and convert format
+ * @param dumplen the number of bytes loaded dump and converted
+ * @return 0 for ok, 1 for fails
+*/
+int convertOldMfuDump(uint8_t **dump, size_t *dumplen);
+
+#define PrintAndLogEx(level, format, args...) PrintAndLogEx(level, format , ## args)
+#else
+
+/**
+* Utility function to print to console. This is used consistently within the library instead
+* of printf, but it actually only calls printf. The reason to have this method is to
+*make it simple to plug this library into proxmark, which has this function already to
+* write also to a logfile. When doing so, just point this function to use PrintAndLog
+* @param fmt
+*/
+#define PrintAndLogEx(level, format, args...) { }
+
+
+
+#endif //ON_DEVICE
+
+#endif // FILEUTILS_H