File FileTable.h¶
File List > external-docs > libDaisy > src > util > FileTable.h
Go to the documentation of this file
Source Code¶
#pragma once
#pragma once
#include <cctype>
#include <cstring>
#include "ff.h"
namespace daisy
{
template <size_t max_slots>
class FileTable
{
public:
static constexpr const size_t kMaxCustomFileNameLen = _MAX_LFN;
static constexpr const size_t kMaxFileSlots = max_slots;
void Clear()
{
for(auto &item : table)
{
std::fill(item.name, item.name + kMaxCustomFileNameLen, 0x00);
item.size = 0;
}
num_files_found = 0;
}
bool Fill(const char *path, const char *endswith = nullptr)
{
FRESULT res = FR_OK;
if(path == nullptr)
{
return false;
}
FILINFO fno;
res = f_opendir(&dir, path);
size_t cnt = 0;
if(res == FR_OK)
{
for(;;)
{
res = f_readdir(&dir, &fno);
if(fno.fname[0] == 0)
break; //< escape w/ no file
bool valid_file_attrs = !(fno.fattrib & AM_HID)
&& !(fno.fattrib & AM_DIR)
&& !(fno.fattrib & AM_SYS);
bool valid_size = fno.fsize > 0;
bool valid_name = false;
if(endswith != nullptr)
{
uint32_t suffix_len = strlen(endswith);
valid_name = strstr(fno.fname, endswith) != nullptr
&& strlen(fno.fname) > suffix_len
&& strlen(fno.fname) < kMaxCustomFileNameLen;
}
else
{
valid_name = strlen(fno.fname) < kMaxCustomFileNameLen;
}
if(valid_file_attrs && valid_size && valid_name)
{
// Copy this file into the slot of the table, and increment
strcpy(table[cnt].name, fno.fname);
table[cnt].size = fno.fsize;
cnt++;
}
if(cnt > kMaxFileSlots - 1)
break;
}
f_closedir(&dir);
}
num_files_found = cnt;
SortTable();
return res == FR_OK;
}
bool WriteLog(const char *log_file_name)
{
FRESULT res
= f_open(&file, log_file_name, (FA_CREATE_ALWAYS | FA_WRITE));
if(res == FR_OK)
{
if(num_files_found > 0)
{
for(size_t i = 0; i < num_files_found; i++)
{
char line_buff[kMaxCustomFileNameLen + 32];
std::fill(line_buff, line_buff + sizeof(line_buff), 0x00);
sprintf(line_buff,
"%d:\t%s\t%d bytes\n",
i + 1,
table[i].name,
table[i].size);
UINT bw = 0;
res = f_write(&file, line_buff, strlen(line_buff), &bw);
if(res != FR_OK)
{
return f_close(&file) == FR_OK;
}
}
}
else
{
const char *text = "No matching files found...";
UINT bw = 0;
res = f_write(&file, text, strlen(text), &bw);
}
f_close(&file);
}
return res == FR_OK;
}
inline bool IsFileInSlot(size_t idx) const { return table[idx].size > 0; }
inline size_t GetFileSize(size_t idx) const { return table[idx].size; }
inline const char *GetFileName(size_t idx) const { return table[idx].name; }
inline size_t GetNumFiles() const { return num_files_found; }
inline bool IsLoadPending() const { return load_pending_; }
inline void ClearLoadPending()
{
load_pending_ = false;
slot_for_load_save_ = -1;
}
inline void SetLoadPending(int slot)
{
load_pending_ = true;
slot_for_load_save_ = slot;
}
inline bool IsSavePending() const { return save_pending_; }
inline void ClearSavePending()
{
save_pending_ = false;
slot_for_load_save_ = -1;
}
inline void SetSavePending(int slot)
{
save_pending_ = true;
slot_for_load_save_ = slot;
}
inline int GetSlotForSaveLoad() const { return slot_for_load_save_; }
private:
struct FileInfo
{
char name[kMaxCustomFileNameLen];
size_t size;
};
void SortTable()
{
if(num_files_found < 2)
return;
for(size_t i = 1; i < num_files_found; ++i)
{
FileInfo key = table[i];
size_t j = i;
while(j > 0 && CaseInsensitiveCmp(table[j - 1].name, key.name) > 0)
{
table[j] = table[j - 1];
--j;
}
table[j] = key;
}
}
FIL file;
DIR dir;
FileInfo table[kMaxFileSlots];
size_t num_files_found;
// Flags for saving/loading of files (not the best place for these)
// but this saves adding more back-and-forth between the new UiPage
// and the actual diskio
bool load_pending_;
bool save_pending_;
int slot_for_load_save_;
// Internal helper for sorting files on to a known order.
static inline int CaseInsensitiveCmp(const char *a, const char *b)
{
// ASCII-only case fold adequate for FAT volume typical usage
unsigned char ca, cb;
while(*a && *b)
{
ca = static_cast<unsigned char>(*a);
cb = static_cast<unsigned char>(*b);
ca = static_cast<unsigned char>(std::tolower(ca));
cb = static_cast<unsigned char>(std::tolower(cb));
if(ca != cb)
return (ca < cb) ? -1 : 1;
++a;
++b;
}
if(*a == *b)
return 0;
return (*a == '\0') ? -1 : 1;
}
};
} // namespace daisy