Skip to content

Commit

Permalink
Merge pull request #843 from Daft-Freak/can-launch
Browse files Browse the repository at this point in the history
Add can_launch API
  • Loading branch information
Daft-Freak committed May 22, 2024
2 parents 9134c1c + c1f8de5 commit 8bec3c4
Show file tree
Hide file tree
Showing 3 changed files with 95 additions and 44 deletions.
10 changes: 10 additions & 0 deletions 32blit/engine/api_private.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ namespace blit {
Pen *palette = nullptr;
};

enum class CanLaunchResult {
Success = 0,
UnknownType, /// no known handler for this file
InvalidFile, /// file is not valid/doesn't exist
IncompatibleBlit, /// file is incompatible with this device
};

#pragma pack(push, 4)
struct API {
uint16_t version_major;
Expand Down Expand Up @@ -135,6 +142,9 @@ namespace blit {

// another launcher API
void (*list_installed_games)(std::function<void(const uint8_t *, uint32_t, uint32_t)> callback);
// if launch is expected to succeed on this file
// files this returns success for should be .blit files or have a registered handler (get_type_handler_metadata should return valid metadata)
CanLaunchResult (*can_launch)(const char *path);
};
#pragma pack(pop)

Expand Down
60 changes: 56 additions & 4 deletions firmware/firmware.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ static bool parse_flash_metadata(uint32_t offset, GameInfo &info) {
return true;
}

static bool parse_file_metadata(FIL &fh, GameInfo &info) {
static bool parse_file_header(FIL &fh, BlitGameHeader &header, uint32_t &header_offset) {
UINT bytes_read;
uint8_t buf[10];

Expand All @@ -119,16 +119,28 @@ static bool parse_file_metadata(FIL &fh, GameInfo &info) {
uint32_t num_relocs;
f_read(&fh, (void *)&num_relocs, 4, &bytes_read);

int relocs_size = num_relocs * 4 + 8;
f_lseek(&fh, relocs_size);
header_offset = num_relocs * 4 + 8;
f_lseek(&fh, header_offset);

// read header
BlitGameHeader header;
f_read(&fh, &header, sizeof(header), &bytes_read);

if(header.magic != blit_game_magic)
return false;

return true;
}

static bool parse_file_metadata(FIL &fh, GameInfo &info) {
UINT bytes_read;
uint8_t buf[10];

// read header
BlitGameHeader header;
uint32_t relocs_size;
if(!parse_file_header(fh, header, relocs_size))
return false;

info.size = header.end - qspi_flash_address;

bool result = false;
Expand Down Expand Up @@ -556,6 +568,45 @@ static void list_installed_games(std::function<void(const uint8_t *, uint32_t, u
callback((const uint8_t *)(qspi_flash_address + game.offset), game.offset / qspi_flash_sector_size, game.size);
}

static CanLaunchResult can_launch(const char *path) {
if(strncmp(path, "flash:/", 7) == 0) {
// assume anything flashed is compatible for now
return CanLaunchResult::Success;
}

// get the extension
std::string_view sv(path);
auto last_dot = sv.find_last_of('.');
auto ext = last_dot == std::string::npos ? "" : std::string(sv.substr(last_dot + 1));
for(auto &c : ext)
c = tolower(c);

if(ext == "blit") {
BlitGameHeader header;
uint32_t header_offset;
FIL file;
FRESULT res = f_open(&file, path, FA_READ);
if(res != FR_OK)
return CanLaunchResult::InvalidFile;

if(parse_file_header(file, header, header_offset)) {
f_close(&file);
return CanLaunchResult::Success;
}

f_close(&file);
return CanLaunchResult::IncompatibleBlit;
}

// not a blit file, so we need to check for handlers
for(auto &handler : handlers) {
if(strncmp(ext.c_str(), handler.type, 4) == 0)
return CanLaunchResult::Success;
}

return CanLaunchResult::UnknownType;
}

static const uint8_t *flash_to_tmp(const std::string &filename, uint32_t &size) {
// one file at a time
// TODO: this could be improved
Expand Down Expand Up @@ -642,6 +693,7 @@ void init() {
api.tmp_file_closed = tmp_file_closed;

api.list_installed_games = list_installed_games;
api.can_launch = can_launch;

scan_flash();
flash_scanned = true;
Expand Down
69 changes: 29 additions & 40 deletions launcher/launcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,86 +146,75 @@ static void load_file_list(const std::string &directory) {

game_list.clear();

auto files = list_files(directory, [](auto &file) {
auto files = list_files(directory, [&](auto &file) {
if(file.flags & FileFlags::directory)
return false;

if(file.name.length() < 6) // minimum length for single-letter game (a.blit)
return false;

if(file.name[0] == '.') // hidden file
return false;

if(file.name.find_last_of('.') == std::string::npos) // no extension
return false;
auto path = directory == "/" ? file.name : directory + "/" + file.name;
auto res = api.can_launch(path.c_str());

return true;
if(res == CanLaunchResult::UnknownType) {
// special case for images
auto last_dot = file.name.find_last_of('.');

auto ext = last_dot == std::string::npos ? "" : file.name.substr(last_dot + 1);

for(auto &c : ext)
c = tolower(c);

if(ext == "bmp" || ext == "blim")
return true;
}

return res == CanLaunchResult::Success;
});

game_list.reserve(files.size()); // worst case

for(auto &file : files) {
auto last_dot = file.name.find_last_of('.');

auto ext = file.name.substr(last_dot + 1);
auto ext = last_dot == std::string::npos ? "" : file.name.substr(last_dot + 1);

for(auto &c : ext)
c = tolower(c);

GameInfo game;
game.title = file.name.substr(0, file.name.length() - ext.length() - 1);
game.filename = directory == "/" ? file.name : directory + "/" + file.name;
game.size = file.size;

if(ext == "blit") {
GameInfo game;
game.type = GameType::game;
game.title = file.name.substr(0, file.name.length() - 5);
game.filename = directory == "/" ? file.name : directory + "/" + file.name;
game.size = file.size;

// check for metadata
BlitGameMetadata meta;
if(parse_file_metadata(game.filename, meta)) {
if(parse_file_metadata(game.filename, meta))
game.title = meta.title;
}

game_list.push_back(game);
continue;
}

if(ext == "bmp" || ext == "blim") {
GameInfo game;
} else if(ext == "bmp" || ext == "blim") {
game.type = GameType::screenshot;
game.title = file.name.substr(0, file.name.length() - ext.length() - 1);
game.filename = directory == "/" ? file.name : directory + "/" + file.name;
game.size = file.size;

// Special case check for an installed handler for these types, ie: a sprite editor
game.can_launch = api.get_type_handler_metadata && api.get_type_handler_metadata(ext.c_str());
game_list.push_back(game);
continue;
}

if(!api.get_type_handler_metadata) continue;

// check for installed handler
auto handler_meta = api.get_type_handler_metadata(ext.c_str());

if(handler_meta) {
GameInfo game;
} else {
// it's launch-able so there must be a handler
game.type = GameType::file;
game.filename = directory == "/" ? file.name : directory + "/" + file.name;
strncpy(game.ext, ext.c_str(), 5);
game.ext[4] = 0;
game.size = file.size;
game.can_launch = true;

// check for a metadata file (fall back to handler's metadata)
BlitGameMetadata meta;
auto meta_filename = game.filename + ".blmeta";
if(parse_file_metadata(meta_filename, meta))
game.title = meta.title;
else
game.title = file.name;

game_list.push_back(game);
}

game_list.push_back(game);
}

int total_items = (int)game_list.size();
Expand Down

0 comments on commit 8bec3c4

Please sign in to comment.