Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/menu/png_decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,10 @@ png_err_t png_decoder_start_mem (void *buf, size_t buf_size, int max_width, int
if (decoder != NULL) return PNG_ERR_BUSY;

decoder = calloc(1, sizeof(png_decoder_t));
if (decoder == NULL) return PNG_ERR_OUT_OF_MEM;
if (decoder == NULL) {
free(buf);
return PNG_ERR_OUT_OF_MEM;
}

decoder->callback = callback;
decoder->callback_data = callback_data;
Expand Down Expand Up @@ -252,8 +255,12 @@ void png_decoder_poll (void) {
}

if (err == SPNG_EOI) {
decoder->callback(PNG_OK, decoder->image, decoder->callback_data);
png_callback_t *callback = decoder->callback;
void *callback_data = decoder->callback_data;
surface_t *image = decoder->image;
decoder->image = NULL;
png_decoder_deinit(false);
callback(PNG_OK, image, callback_data);
} else if (err != SPNG_OK) {
png_callback_t *callback = decoder->callback;
void *callback_data = decoder->callback_data;
Expand Down
127 changes: 127 additions & 0 deletions src/menu/rom_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,7 @@ static bool load_metadata_from_zip_file (const char *zip_path, rom_info_t *rom_i
bool success = false;
if (meta_ini) {
bool ok = true;
ok &= replace_owned_string(&rom_info->meta.metadata_zip_path, zip_path);
ok &= replace_owned_string(&rom_info->meta.name, ini_get_string(meta_ini, "meta", "name", ""));
ok &= replace_owned_string(&rom_info->meta.author, ini_get_string(meta_ini, "meta", "author", "Not specified"));
ok &= replace_owned_string(&rom_info->meta.release_date, ini_get_string(meta_ini, "meta", "release-date", "Not specified"));
Expand All @@ -906,6 +907,34 @@ static bool load_metadata_from_zip_file (const char *zip_path, rom_info_t *rom_i
rom_info->meta.age_rating = ini_get_int(meta_ini, "meta", "age-rating", 0);
rom_info->meta.num_players = ini_get_int(meta_ini, "meta", "num-players", 1);
ok &= replace_owned_string(&rom_info->meta.short_description, ini_get_string(meta_ini, "meta", "short-desc", ""));
static const char *boxart_keys[] = { "front", "back", "top", "bottom", "left", "right" };
for (size_t i = 0; i < 6; i++) {
ok &= replace_owned_string(&rom_info->meta.boxart[i], ini_get_string(meta_ini, "boxart", boxart_keys[i], ""));
}
for (size_t i = 0; i < rom_info->meta.screenshot_count; i++) {
free(rom_info->meta.screenshots[i]);
rom_info->meta.screenshots[i] = NULL;
}
rom_info->meta.screenshot_count = 0;
const char *screenshots = ini_get_string(meta_ini, "meta", "screenshots", "");
char *list = strdup(screenshots);
if (list != NULL) {
char *save = NULL;
for (char *filename = strtok_r(list, ",", &save);
filename != NULL && rom_info->meta.screenshot_count < ROM_METADATA_MAX_SCREENSHOTS;
filename = strtok_r(NULL, ",", &save)) {
while (*filename == ' ' || *filename == '\t') filename++;
char *end = filename + strlen(filename);
while (end > filename && (end[-1] == ' ' || end[-1] == '\t')) *--end = '\0';
if (*filename != '\0') {
rom_info->meta.screenshots[rom_info->meta.screenshot_count] = strdup(filename);
if (rom_info->meta.screenshots[rom_info->meta.screenshot_count] != NULL) {
rom_info->meta.screenshot_count++;
}
}
}
free(list);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
ini_free(meta_ini);
success = ok;
if (ok) {
Expand Down Expand Up @@ -1049,6 +1078,7 @@ static bool load_rom_meta_from_embedded_zip (const char *rom_path, rom_header_t
bool success = false;
if (meta_ini) {
bool ok = true;
ok &= replace_owned_string(&rom_info->meta.metadata_zip_path, rom_path);
ok &= replace_owned_string(&rom_info->meta.name, ini_get_string(meta_ini, "meta", "name", ""));
ok &= replace_owned_string(&rom_info->meta.author, ini_get_string(meta_ini, "meta", "author", "Not specified"));
ok &= replace_owned_string(&rom_info->meta.release_date, ini_get_string(meta_ini, "meta", "release-date", "Not specified"));
Expand All @@ -1058,6 +1088,34 @@ static bool load_rom_meta_from_embedded_zip (const char *rom_path, rom_header_t
rom_info->meta.num_players = ini_get_int(meta_ini, "meta", "num-players", 1);
ok &= replace_owned_string(&rom_info->meta.short_description, ini_get_string(meta_ini, "meta", "short-desc", ""));
ok &= replace_owned_string(&rom_info->meta.long_description_fn, ini_get_string(meta_ini, "meta", "long-desc-fn", ""));
static const char *boxart_keys[] = { "front", "back", "top", "bottom", "left", "right" };
for (size_t i = 0; i < 6; i++) {
ok &= replace_owned_string(&rom_info->meta.boxart[i], ini_get_string(meta_ini, "boxart", boxart_keys[i], ""));
}
for (size_t i = 0; i < rom_info->meta.screenshot_count; i++) {
free(rom_info->meta.screenshots[i]);
rom_info->meta.screenshots[i] = NULL;
}
rom_info->meta.screenshot_count = 0;
const char *screenshots = ini_get_string(meta_ini, "meta", "screenshots", "");
char *list = strdup(screenshots);
if (list != NULL) {
char *save = NULL;
for (char *filename = strtok_r(list, ",", &save);
filename != NULL && rom_info->meta.screenshot_count < ROM_METADATA_MAX_SCREENSHOTS;
filename = strtok_r(NULL, ",", &save)) {
while (*filename == ' ' || *filename == '\t') filename++;
char *end = filename + strlen(filename);
while (end > filename && (end[-1] == ' ' || end[-1] == '\t')) *--end = '\0';
if (*filename != '\0') {
rom_info->meta.screenshots[rom_info->meta.screenshot_count] = strdup(filename);
if (rom_info->meta.screenshots[rom_info->meta.screenshot_count] != NULL) {
rom_info->meta.screenshot_count++;
}
}
}
free(list);
}
ini_free(meta_ini);
success = ok;
if (ok) {
Expand Down Expand Up @@ -1128,6 +1186,34 @@ static void load_rom_meta_from_file (path_t *path, rom_info_t *rom_info) {
rom_info->meta.num_players = ini_get_int(rom_meta_ini, "meta", "num-players", 1);
ok &= replace_owned_string(&rom_info->meta.short_description, ini_get_string(rom_meta_ini, "meta", "short-desc", ""));
ok &= replace_owned_string(&rom_info->meta.long_description_fn, ini_get_string(rom_meta_ini, "meta", "long-desc-fn", ""));
static const char *boxart_keys[] = { "front", "back", "top", "bottom", "left", "right" };
for (size_t i = 0; i < 6; i++) {
ok &= replace_owned_string(&rom_info->meta.boxart[i], ini_get_string(rom_meta_ini, "boxart", boxart_keys[i], ""));
}
for (size_t i = 0; i < rom_info->meta.screenshot_count; i++) {
free(rom_info->meta.screenshots[i]);
rom_info->meta.screenshots[i] = NULL;
}
rom_info->meta.screenshot_count = 0;
const char *screenshots = ini_get_string(rom_meta_ini, "meta", "screenshots", "");
char *list = strdup(screenshots);
if (list != NULL) {
char *save = NULL;
for (char *filename = strtok_r(list, ",", &save);
filename != NULL && rom_info->meta.screenshot_count < ROM_METADATA_MAX_SCREENSHOTS;
filename = strtok_r(NULL, ",", &save)) {
while (*filename == ' ' || *filename == '\t') filename++;
char *end = filename + strlen(filename);
while (end > filename && (end[-1] == ' ' || end[-1] == '\t')) *--end = '\0';
if (*filename != '\0') {
rom_info->meta.screenshots[rom_info->meta.screenshot_count] = strdup(filename);
if (rom_info->meta.screenshots[rom_info->meta.screenshot_count] != NULL) {
rom_info->meta.screenshot_count++;
}
}
}
free(list);
}
ini_free(rom_meta_ini);
if (ok) {
debugf("[META] Loaded from INI file: name='%s', author='%s'\n", rom_info->meta.name, rom_info->meta.author);
Expand All @@ -1139,6 +1225,36 @@ static void load_rom_meta_from_file (path_t *path, rom_info_t *rom_info) {
path_free(rom_info_meta_path);
}

bool rom_info_extract_metadata_image(const rom_info_t *rom_info, const char *filename,
uint8_t **data, size_t *size) {
if (!rom_info || !rom_info->meta.metadata_zip_path || !filename || !data || !size ||
filename[0] == '/' || strstr(filename, "..") != NULL) {
return false;
}

*data = NULL;
*size = 0;
mz_zip_archive zip = {0};
if (!mz_zip_reader_init_file(&zip, rom_info->meta.metadata_zip_path, 0)) return false;

mz_uint index = mz_zip_reader_locate_file(&zip, filename, NULL, MZ_ZIP_FLAG_CASE_SENSITIVE);
mz_zip_archive_file_stat stat;
bool ok = index != MZ_UINT32_MAX && mz_zip_reader_file_stat(&zip, index, &stat) &&
stat.m_uncomp_size > 0 && stat.m_uncomp_size <= 2 * 1024 * 1024;
if (ok) {
uint8_t *buffer = malloc((size_t) stat.m_uncomp_size);
ok = buffer != NULL && mz_zip_reader_extract_to_mem(&zip, index, buffer, (size_t) stat.m_uncomp_size, 0);
if (ok) {
*data = buffer;
*size = (size_t) stat.m_uncomp_size;
} else {
free(buffer);
}
}
mz_zip_reader_end(&zip);
return ok;
}

void rom_info_free_meta(rom_info_t *rom_info) {
if (!rom_info) {
return;
Expand Down Expand Up @@ -1172,6 +1288,17 @@ void rom_info_free_meta(rom_info_t *rom_info) {
free(rom_info->meta.long_description_fn);
rom_info->meta.long_description_fn = NULL;
}
free(rom_info->meta.metadata_zip_path);
rom_info->meta.metadata_zip_path = NULL;
for (size_t i = 0; i < 6; i++) {
free(rom_info->meta.boxart[i]);
rom_info->meta.boxart[i] = NULL;
}
for (size_t i = 0; i < rom_info->meta.screenshot_count; i++) {
free(rom_info->meta.screenshots[i]);
rom_info->meta.screenshots[i] = NULL;
}
rom_info->meta.screenshot_count = 0;
}

static void load_rom_config_from_file (path_t *path, rom_info_t *rom_info) {
Expand Down
11 changes: 11 additions & 0 deletions src/menu/rom_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
#define ROM_INFO_H__

#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

#include "path.h"

#define ROM_METADATA_MAX_SCREENSHOTS 8

/** @brief ROM error enumeration. */
typedef enum {
ROM_OK, /**< No error */
Expand Down Expand Up @@ -175,10 +178,18 @@ typedef struct {
uint32_t num_players; /**< The number of players supported */
char *short_description; /**< The short game description */
char *long_description_fn; /**< The long game description file name */
char *metadata_zip_path; /**< ZIP containing metadata images, if any */
char *boxart[6]; /**< Spec-defined boxart filenames: front, back, top, bottom, left, right */
char *screenshots[ROM_METADATA_MAX_SCREENSHOTS]; /**< Spec-defined screenshot filenames */
uint8_t screenshot_count; /**< Number of screenshot filenames */
bool size_limit_exceeded; /**< Metadata was skipped because metadata.ini exceeded size cap */
} meta; /**< The ROM metadata */
} rom_info_t;

/** Extract a metadata image from the associated ZIP into a heap buffer. */
bool rom_info_extract_metadata_image(const rom_info_t *rom_info, const char *filename,
uint8_t **data, size_t *size);

/**
* @brief Get the CIC seed for the ROM.
*
Expand Down
4 changes: 4 additions & 0 deletions src/menu/ui_components.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,10 @@ typedef struct {
*/
component_boxart_t *ui_components_boxart_init(const char *storage_prefix, const char *game_code, const char *rom_title, file_image_type_t current_image_view);

/** Initialize boxart from an image buffer owned by the decoder. */
component_boxart_t *ui_components_boxart_init_mem(const char *filename, void *data, size_t size,
int max_width, int max_height);

/**
* @brief Free the box art component resources.
*
Expand Down
10 changes: 10 additions & 0 deletions src/menu/ui_components/background.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,17 @@ static void load_from_cache(component_background_t *c) {
}

c->image = calloc(1, sizeof(surface_t));
if (c->image == NULL) {
fclose(f);
return;
}
*c->image = surface_alloc(FMT_RGBA16, cache_metadata.width, cache_metadata.height);
if (c->image->buffer == NULL) {
free(c->image);
c->image = NULL;
fclose(f);
return;
}

if (cache_metadata.size != (c->image->height * c->image->stride)) {
surface_free(c->image);
Expand Down
33 changes: 33 additions & 0 deletions src/menu/ui_components/boxart.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

#include "../ui_components.h"
#include "../path.h"
#include "../jpeg_decoder.h"
#include "../png_decoder.h"
#include "constants.h"
#include "utils/fs.h"
Expand All @@ -31,6 +32,37 @@ static void png_decoder_callback(png_err_t err, surface_t *decoded_image, void *
b->image = decoded_image;
}

static void jpeg_decoder_callback(jpeg_err_t err, surface_t *decoded_image, void *callback_data) {
component_boxart_t *b = (component_boxart_t *)(callback_data);
b->loading = false;
b->image = (err == JPEG_OK) ? decoded_image : NULL;
}

component_boxart_t *ui_components_boxart_init_mem(const char *filename, void *data, size_t size,
int max_width, int max_height) {
component_boxart_t *b = calloc(1, sizeof(component_boxart_t));
if (!b) {
free(data);
return NULL;
}
b->loading = true;

jpeg_err_t jpeg_err = JPEG_ERR_BAD_FILE;
png_err_t png_err = PNG_ERR_BAD_FILE;
bool is_jpeg = file_has_extensions((char *) filename, (const char *[]) { "jpg", "jpeg", NULL });
if (is_jpeg) {
jpeg_err = jpeg_decoder_start_mem(data, size, max_width, max_height, jpeg_decoder_callback, b);
if (jpeg_err == JPEG_OK) return b;
} else {
png_err = png_decoder_start_mem(data, size, max_width, max_height, png_decoder_callback, b);
if (png_err == PNG_OK) return b;
if (png_err == PNG_ERR_BUSY) free(data);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

free(b);
return NULL;
}

/**
* @brief Initialize and load the boxart component for a game.
*
Expand Down Expand Up @@ -180,6 +212,7 @@ component_boxart_t *ui_components_boxart_init(const char *storage_prefix, const
void ui_components_boxart_free(component_boxart_t *b) {
if (b) {
if (b->loading) {
jpeg_decoder_abort();
png_decoder_abort();
}
if (b->image) {
Expand Down
Loading