Skip to content

Commit 8bec3c4

Browse files
authored
Merge pull request #843 from Daft-Freak/can-launch
Add can_launch API
2 parents 9134c1c + c1f8de5 commit 8bec3c4

File tree

3 files changed

+95
-44
lines changed

3 files changed

+95
-44
lines changed

32blit/engine/api_private.hpp

+10
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ namespace blit {
5353
Pen *palette = nullptr;
5454
};
5555

56+
enum class CanLaunchResult {
57+
Success = 0,
58+
UnknownType, /// no known handler for this file
59+
InvalidFile, /// file is not valid/doesn't exist
60+
IncompatibleBlit, /// file is incompatible with this device
61+
};
62+
5663
#pragma pack(push, 4)
5764
struct API {
5865
uint16_t version_major;
@@ -135,6 +142,9 @@ namespace blit {
135142

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

firmware/firmware.cpp

+56-4
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ static bool parse_flash_metadata(uint32_t offset, GameInfo &info) {
105105
return true;
106106
}
107107

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

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

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

125125
// read header
126-
BlitGameHeader header;
127126
f_read(&fh, &header, sizeof(header), &bytes_read);
128127

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

131+
return true;
132+
}
133+
134+
static bool parse_file_metadata(FIL &fh, GameInfo &info) {
135+
UINT bytes_read;
136+
uint8_t buf[10];
137+
138+
// read header
139+
BlitGameHeader header;
140+
uint32_t relocs_size;
141+
if(!parse_file_header(fh, header, relocs_size))
142+
return false;
143+
132144
info.size = header.end - qspi_flash_address;
133145

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

571+
static CanLaunchResult can_launch(const char *path) {
572+
if(strncmp(path, "flash:/", 7) == 0) {
573+
// assume anything flashed is compatible for now
574+
return CanLaunchResult::Success;
575+
}
576+
577+
// get the extension
578+
std::string_view sv(path);
579+
auto last_dot = sv.find_last_of('.');
580+
auto ext = last_dot == std::string::npos ? "" : std::string(sv.substr(last_dot + 1));
581+
for(auto &c : ext)
582+
c = tolower(c);
583+
584+
if(ext == "blit") {
585+
BlitGameHeader header;
586+
uint32_t header_offset;
587+
FIL file;
588+
FRESULT res = f_open(&file, path, FA_READ);
589+
if(res != FR_OK)
590+
return CanLaunchResult::InvalidFile;
591+
592+
if(parse_file_header(file, header, header_offset)) {
593+
f_close(&file);
594+
return CanLaunchResult::Success;
595+
}
596+
597+
f_close(&file);
598+
return CanLaunchResult::IncompatibleBlit;
599+
}
600+
601+
// not a blit file, so we need to check for handlers
602+
for(auto &handler : handlers) {
603+
if(strncmp(ext.c_str(), handler.type, 4) == 0)
604+
return CanLaunchResult::Success;
605+
}
606+
607+
return CanLaunchResult::UnknownType;
608+
}
609+
559610
static const uint8_t *flash_to_tmp(const std::string &filename, uint32_t &size) {
560611
// one file at a time
561612
// TODO: this could be improved
@@ -642,6 +693,7 @@ void init() {
642693
api.tmp_file_closed = tmp_file_closed;
643694

644695
api.list_installed_games = list_installed_games;
696+
api.can_launch = can_launch;
645697

646698
scan_flash();
647699
flash_scanned = true;

launcher/launcher.cpp

+29-40
Original file line numberDiff line numberDiff line change
@@ -146,86 +146,75 @@ static void load_file_list(const std::string &directory) {
146146

147147
game_list.clear();
148148

149-
auto files = list_files(directory, [](auto &file) {
149+
auto files = list_files(directory, [&](auto &file) {
150150
if(file.flags & FileFlags::directory)
151151
return false;
152152

153-
if(file.name.length() < 6) // minimum length for single-letter game (a.blit)
154-
return false;
155-
156153
if(file.name[0] == '.') // hidden file
157154
return false;
158155

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

162-
return true;
159+
if(res == CanLaunchResult::UnknownType) {
160+
// special case for images
161+
auto last_dot = file.name.find_last_of('.');
162+
163+
auto ext = last_dot == std::string::npos ? "" : file.name.substr(last_dot + 1);
164+
165+
for(auto &c : ext)
166+
c = tolower(c);
167+
168+
if(ext == "bmp" || ext == "blim")
169+
return true;
170+
}
171+
172+
return res == CanLaunchResult::Success;
163173
});
164174

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

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

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

172182
for(auto &c : ext)
173183
c = tolower(c);
174184

185+
GameInfo game;
186+
game.title = file.name.substr(0, file.name.length() - ext.length() - 1);
187+
game.filename = directory == "/" ? file.name : directory + "/" + file.name;
188+
game.size = file.size;
189+
175190
if(ext == "blit") {
176-
GameInfo game;
177191
game.type = GameType::game;
178-
game.title = file.name.substr(0, file.name.length() - 5);
179-
game.filename = directory == "/" ? file.name : directory + "/" + file.name;
180-
game.size = file.size;
181192

182193
// check for metadata
183194
BlitGameMetadata meta;
184-
if(parse_file_metadata(game.filename, meta)) {
195+
if(parse_file_metadata(game.filename, meta))
185196
game.title = meta.title;
186-
}
187197

188-
game_list.push_back(game);
189-
continue;
190-
}
191-
192-
if(ext == "bmp" || ext == "blim") {
193-
GameInfo game;
198+
} else if(ext == "bmp" || ext == "blim") {
194199
game.type = GameType::screenshot;
195-
game.title = file.name.substr(0, file.name.length() - ext.length() - 1);
196-
game.filename = directory == "/" ? file.name : directory + "/" + file.name;
197-
game.size = file.size;
198200

199201
// Special case check for an installed handler for these types, ie: a sprite editor
200202
game.can_launch = api.get_type_handler_metadata && api.get_type_handler_metadata(ext.c_str());
201-
game_list.push_back(game);
202-
continue;
203-
}
204-
205-
if(!api.get_type_handler_metadata) continue;
206-
207-
// check for installed handler
208-
auto handler_meta = api.get_type_handler_metadata(ext.c_str());
209-
210-
if(handler_meta) {
211-
GameInfo game;
203+
} else {
204+
// it's launch-able so there must be a handler
212205
game.type = GameType::file;
213-
game.filename = directory == "/" ? file.name : directory + "/" + file.name;
214206
strncpy(game.ext, ext.c_str(), 5);
215207
game.ext[4] = 0;
216-
game.size = file.size;
217208
game.can_launch = true;
218209

219210
// check for a metadata file (fall back to handler's metadata)
220211
BlitGameMetadata meta;
221212
auto meta_filename = game.filename + ".blmeta";
222213
if(parse_file_metadata(meta_filename, meta))
223214
game.title = meta.title;
224-
else
225-
game.title = file.name;
226-
227-
game_list.push_back(game);
228215
}
216+
217+
game_list.push_back(game);
229218
}
230219

231220
int total_items = (int)game_list.size();

0 commit comments

Comments
 (0)