mirror of
https://github.com/Oibaf66/frodo-wii.git
synced 2024-11-29 06:54:22 +01:00
461 lines
11 KiB
C++
461 lines
11 KiB
C++
#if defined(GEKKO)
|
|
# include <network.h>
|
|
#else
|
|
#include <arpa/inet.h>
|
|
#endif
|
|
#include <sys/stat.h>
|
|
#include <SDL.h>
|
|
#include <SDL_image.h>
|
|
|
|
#include <utils.hh>
|
|
|
|
#include "game_info.hh"
|
|
|
|
#define VERSION_BASE (0x1978)
|
|
#define VERSION(x) (VERSION_BASE + (x))
|
|
/* Current magic */
|
|
#define VERSION_MAGIC VERSION(2)
|
|
|
|
struct game_info
|
|
{
|
|
/* These two MUST stay the same */
|
|
uint32_t sz;
|
|
uint16_t version_magic;
|
|
uint16_t flags;
|
|
|
|
uint16_t author_off;
|
|
uint16_t name_off;
|
|
uint16_t screenshot_off; /* In PNG format */
|
|
uint16_t filename_off;
|
|
uint16_t score;
|
|
uint16_t year;
|
|
uint8_t genre;
|
|
uint8_t players;
|
|
uint16_t creator_off;
|
|
uint16_t musician_off;
|
|
uint16_t graphics_artist_off;
|
|
uint8_t data[]; /* 4-byte aligned */
|
|
};
|
|
|
|
struct game_info_v0
|
|
{
|
|
uint32_t sz;
|
|
uint16_t version_magic;
|
|
|
|
uint16_t author_off;
|
|
uint16_t name_off;
|
|
uint16_t screenshot_off; /* In PNG format */
|
|
uint16_t filename_off;
|
|
uint16_t score;
|
|
uint8_t data[]; /* 4-byte aligned */
|
|
};
|
|
|
|
struct game_info_v1
|
|
{
|
|
uint32_t sz;
|
|
uint16_t version_magic;
|
|
uint16_t flags;
|
|
|
|
uint16_t author_off;
|
|
uint16_t name_off;
|
|
uint16_t screenshot_off; /* In PNG format */
|
|
uint16_t filename_off;
|
|
uint16_t score;
|
|
uint16_t year;
|
|
uint8_t data[]; /* 4-byte aligned */
|
|
};
|
|
|
|
struct game_info_v2
|
|
{
|
|
uint32_t sz;
|
|
uint16_t version_magic;
|
|
uint16_t flags;
|
|
|
|
uint16_t author_off;
|
|
uint16_t name_off;
|
|
uint16_t screenshot_off; /* In PNG format */
|
|
uint16_t filename_off;
|
|
uint16_t score;
|
|
uint16_t year;
|
|
uint8_t genre;
|
|
uint8_t players;
|
|
uint16_t creator_off;
|
|
uint16_t musician_off;
|
|
uint16_t graphics_artist_off;
|
|
uint8_t data[]; /* 4-byte aligned */
|
|
};
|
|
|
|
static void demarshal_v0(struct game_info_v0 *src)
|
|
{
|
|
src->sz = ntohl(src->sz);
|
|
src->version_magic = ntohs(src->version_magic);
|
|
src->author_off = ntohs(src->author_off);
|
|
src->name_off = ntohs(src->name_off);
|
|
src->filename_off = ntohs(src->filename_off);
|
|
src->screenshot_off = ntohs(src->screenshot_off);
|
|
src->score = ntohs(src->score);
|
|
}
|
|
|
|
|
|
static void demarshal_v1(struct game_info_v1 *src)
|
|
{
|
|
demarshal_v0((struct game_info_v0 *)src);
|
|
src->flags = ntohs(src->flags);
|
|
src->year = ntohs(src->year);
|
|
}
|
|
|
|
static void demarshal_v2(struct game_info_v2 *src)
|
|
{
|
|
demarshal_v1((struct game_info_v1 *)src);
|
|
src->musician_off = ntohs(src->musician_off);
|
|
src->creator_off = ntohs(src->creator_off);
|
|
src->graphics_artist_off = ntohs(src->graphics_artist_off);
|
|
}
|
|
|
|
|
|
static bool from_v0(GameInfo *dst, struct game_info_v0 *p)
|
|
{
|
|
demarshal_v0(p);
|
|
|
|
dst->publisher = xstrdup((char*)p->data + p->author_off);
|
|
dst->name = xstrdup((char*)p->data + p->name_off);
|
|
dst->filename = xstrdup((char*)p->data + p->filename_off);
|
|
dst->score = p->score;
|
|
dst->year = 1984;
|
|
dst->graphics_artist = xstrdup(" ");
|
|
dst->musician = xstrdup(" ");
|
|
dst->creator = xstrdup(" ");
|
|
dst->genre = GENRE_UNKNOWN;
|
|
dst->players = 1;
|
|
|
|
dst->screenshot = sdl_surface_from_data(p->data + p->screenshot_off,
|
|
p->sz - p->screenshot_off);
|
|
if (!dst->screenshot)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool from_v1(GameInfo *dst, struct game_info_v1 *p)
|
|
{
|
|
demarshal_v1(p);
|
|
|
|
dst->publisher = xstrdup((char*)p->data + p->author_off);
|
|
dst->name = xstrdup((char*)p->data + p->name_off);
|
|
dst->filename = xstrdup((char*)p->data + p->filename_off);
|
|
dst->score = p->score;
|
|
dst->year = p->year;
|
|
dst->graphics_artist = xstrdup(" ");
|
|
dst->musician = xstrdup(" ");
|
|
dst->creator = xstrdup(" ");
|
|
dst->genre = GENRE_UNKNOWN;
|
|
dst->players = 1;
|
|
|
|
dst->screenshot = sdl_surface_from_data(p->data + p->screenshot_off,
|
|
p->sz - p->screenshot_off);
|
|
if (!dst->screenshot)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool from_v2(GameInfo *dst, struct game_info_v2 *p)
|
|
{
|
|
demarshal_v2(p);
|
|
|
|
dst->publisher = xstrdup((char*)p->data + p->author_off);
|
|
dst->name = xstrdup((char*)p->data + p->name_off);
|
|
dst->filename = xstrdup((char*)p->data + p->filename_off);
|
|
dst->score = p->score;
|
|
dst->year = p->year;
|
|
dst->graphics_artist = xstrdup((char*)p->data + p->graphics_artist_off);
|
|
dst->musician = xstrdup((char*)p->data + p->musician_off);
|
|
dst->creator = xstrdup((char*)p->data + p->creator_off);
|
|
dst->genre = p->genre;
|
|
dst->players = p->players;
|
|
|
|
dst->screenshot = sdl_surface_from_data(p->data + p->screenshot_off,
|
|
p->sz - p->screenshot_off);
|
|
if (!dst->screenshot)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
GameInfo::GameInfo(const char *filename,
|
|
const char *name, const char *publisher,
|
|
const char *creator, const char *graphics_artist,
|
|
const char *musician, SDL_Surface *image)
|
|
{
|
|
this->filename = xstrdup(filename);
|
|
if (strcmp(name, " ") == 0)
|
|
this->name = xstrdup(filename);
|
|
else
|
|
this->name = xstrdup(name);
|
|
this->publisher = xstrdup(publisher);
|
|
this->creator = xstrdup(creator);
|
|
this->graphics_artist = xstrdup(graphics_artist);
|
|
this->musician = xstrdup(musician);
|
|
this->graphics_artist = xstrdup(graphics_artist);
|
|
this->creator = xstrdup(creator);
|
|
this->musician = xstrdup(musician);
|
|
this->screenshot = image;
|
|
this->genre = GENRE_UNKNOWN;
|
|
this->players = 1;
|
|
this->score = 0;
|
|
this->year = 1982;
|
|
}
|
|
|
|
GameInfo::GameInfo(GameInfo *gi)
|
|
{
|
|
if (!gi)
|
|
{
|
|
this->resetDefaults();
|
|
return;
|
|
}
|
|
|
|
this->name = xstrdup(gi->name);
|
|
this->publisher = xstrdup(gi->publisher);
|
|
this->filename = xstrdup(gi->filename);
|
|
this->graphics_artist = xstrdup(gi->graphics_artist);
|
|
this->creator = xstrdup(gi->creator);
|
|
this->musician = xstrdup(gi->musician);
|
|
this->screenshot = NULL;
|
|
this->players = gi->players;
|
|
this->score = gi->score;
|
|
this->year = gi->year;
|
|
this->genre = gi->genre;
|
|
|
|
if (gi->screenshot)
|
|
this->screenshot = SDL_DisplayFormat(gi->screenshot);
|
|
}
|
|
|
|
GameInfo::~GameInfo()
|
|
{
|
|
this->freeAll();
|
|
}
|
|
|
|
void GameInfo::freeAll()
|
|
{
|
|
free((void*)this->name);
|
|
free((void*)this->publisher);
|
|
free((void*)this->filename);
|
|
free((void*)this->creator);
|
|
free((void*)this->graphics_artist);
|
|
free((void*)this->musician);
|
|
|
|
SDL_FreeSurface(this->screenshot);
|
|
}
|
|
|
|
void GameInfo::resetDefaults()
|
|
{
|
|
this->freeAll();
|
|
|
|
this->name = xstrdup(" ");
|
|
this->publisher = xstrdup(" ");
|
|
this->filename = xstrdup("unknown");
|
|
this->creator = xstrdup(" ");
|
|
this->musician = xstrdup(" ");
|
|
this->graphics_artist = xstrdup(" ");
|
|
this->screenshot = NULL;
|
|
|
|
this->genre = GENRE_UNKNOWN;
|
|
this->players = 1;
|
|
this->score = 0;
|
|
this->year = 1982;
|
|
}
|
|
|
|
void *GameInfo::dump(size_t *out_sz)
|
|
{
|
|
size_t total_sz = sizeof(struct game_info);
|
|
size_t png_sz;
|
|
struct game_info *out;
|
|
void *png_data;
|
|
|
|
if (!this->screenshot)
|
|
return NULL;
|
|
|
|
/* Convert surface to PNG */
|
|
png_data = sdl_surface_to_png(this->screenshot, &png_sz);
|
|
panic_if(!png_data, "Cannot create PNG from surface\n");
|
|
|
|
total_sz += strlen(this->publisher) + 1;
|
|
total_sz += strlen(this->name) + 1;
|
|
total_sz += strlen(this->filename) + 1;
|
|
total_sz += strlen(this->creator) + 1;
|
|
total_sz += strlen(this->musician) + 1;
|
|
total_sz += strlen(this->graphics_artist) + 1;
|
|
|
|
total_sz += png_sz;
|
|
/* 4-byte align */
|
|
total_sz += 4 - (total_sz & 3);
|
|
|
|
/* Allocate everything */
|
|
out = (struct game_info*)xmalloc(total_sz);
|
|
out->sz = total_sz;
|
|
out->score = this->score;
|
|
out->year = this->year;
|
|
out->genre = this->genre;
|
|
out->players = this->players;
|
|
out->version_magic = VERSION_MAGIC;
|
|
|
|
out->author_off = 0; /* Starts AFTER the header */
|
|
out->name_off = out->author_off + strlen(this->publisher) + 1;
|
|
out->filename_off = out->name_off + strlen(this->name) + 1;
|
|
out->creator_off = out->filename_off + strlen(this->filename) + 1;
|
|
out->musician_off = out->creator_off + strlen(this->creator) + 1;
|
|
out->graphics_artist_off = out->musician_off + strlen(this->musician) + 1;
|
|
out->screenshot_off = out->graphics_artist_off + strlen(this->graphics_artist) + 1;
|
|
|
|
|
|
memcpy(out->data + out->author_off, this->publisher, strlen(this->publisher) + 1);
|
|
memcpy(out->data + out->name_off, this->name, strlen(this->name) + 1);
|
|
memcpy(out->data + out->filename_off, this->filename, strlen(this->filename) + 1);
|
|
memcpy(out->data + out->creator_off, this->creator, strlen(this->creator) + 1);
|
|
memcpy(out->data + out->musician_off, this->musician, strlen(this->musician) + 1);
|
|
memcpy(out->data + out->graphics_artist_off, this->graphics_artist, strlen(this->graphics_artist) + 1);
|
|
memcpy(out->data + out->screenshot_off, png_data, png_sz);
|
|
|
|
*out_sz = out->sz;
|
|
/* Marshall it all */
|
|
out->sz = htonl(out->sz);
|
|
out->author_off = htons(out->author_off);
|
|
out->version_magic = htons(out->version_magic);
|
|
out->name_off = htons(out->name_off);
|
|
out->filename_off = htons(out->filename_off);
|
|
out->creator_off = htons(out->creator_off);
|
|
out->musician_off = htons(out->musician_off);
|
|
out->graphics_artist_off = htons(out->graphics_artist_off);
|
|
out->screenshot_off = htons(out->screenshot_off);
|
|
out->score = htons(out->score);
|
|
out->year = htons(out->year);
|
|
|
|
return (void *)out;
|
|
}
|
|
|
|
bool GameInfo::fromDump(struct game_info *gi)
|
|
{
|
|
bool ret;
|
|
|
|
this->freeAll();
|
|
|
|
/* Demarshal and convert */
|
|
switch (ntohs(gi->version_magic))
|
|
{
|
|
case VERSION(0):
|
|
ret = from_v0(this, (struct game_info_v0 *)gi); break;
|
|
case VERSION(1):
|
|
ret = from_v1(this, (struct game_info_v1 *)gi); break;
|
|
case VERSION(2):
|
|
ret = from_v2(this, (struct game_info_v2 *)gi); break;
|
|
default:
|
|
/* Garbage, let's return */
|
|
warning("game info garbage magic: %2x\n",
|
|
ntohs(gi->version_magic));
|
|
return false;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
GameInfo *GameInfo::loadFromFile(const char *fileName)
|
|
{
|
|
struct stat st;
|
|
struct game_info *p;
|
|
GameInfo *out = NULL;
|
|
FILE *fp;
|
|
|
|
if (stat(fileName, &st) < 0)
|
|
return NULL;
|
|
if (st.st_size <= (signed)sizeof(struct game_info))
|
|
{
|
|
warning("Size of %s is too small: %d vs minimum %d bytes\n",
|
|
fileName, (int)st.st_size, (signed)sizeof(struct game_info) + 4);
|
|
return NULL;
|
|
}
|
|
if (st.st_size % 4 != 0)
|
|
{
|
|
warning("Size of %s is unreasonable: %d\n", fileName, (int)st.st_size);
|
|
return NULL;
|
|
}
|
|
|
|
fp = fopen(fileName, "r");
|
|
if (!fp)
|
|
return NULL;
|
|
p = (struct game_info*)xmalloc(st.st_size);
|
|
if (fread(p, 1, st.st_size, fp) == (unsigned)st.st_size)
|
|
{
|
|
out = new GameInfo();
|
|
if (out->fromDump(p) == false)
|
|
{
|
|
warning("Converting %s to GameInfo failed\n",
|
|
fileName);
|
|
delete out;
|
|
out = NULL;
|
|
}
|
|
}
|
|
else
|
|
warning("Could not read %s\n", fileName);
|
|
|
|
free(p);
|
|
fclose(fp);
|
|
|
|
return out;
|
|
}
|
|
|
|
void GameInfo::setGeneric(const char **what, const char *who)
|
|
{
|
|
if (strlen(who) == 0)
|
|
who = " ";
|
|
free((void*)*what);
|
|
*what = xstrdup(who);
|
|
if (strcmp(who, " ") != 0)
|
|
this->score++;
|
|
}
|
|
|
|
void GameInfo::setAuthor(const char *who)
|
|
{
|
|
this->setGeneric(&this->publisher, who);
|
|
}
|
|
|
|
void GameInfo::setCreator(const char *who)
|
|
{
|
|
this->setGeneric(&this->creator, who);
|
|
}
|
|
|
|
void GameInfo::setMusician(const char *who)
|
|
{
|
|
this->setGeneric(&this->musician, who);
|
|
}
|
|
|
|
void GameInfo::setGraphicsArtist(const char *who)
|
|
{
|
|
this->setGeneric(&this->graphics_artist, who);
|
|
}
|
|
|
|
void GameInfo::setYear(uint16_t year)
|
|
{
|
|
this->year = year;
|
|
this->score++;
|
|
}
|
|
|
|
void GameInfo::setName(const char *name)
|
|
{
|
|
if (strlen(name) == 0)
|
|
name = " ";
|
|
|
|
free((void*)this->name);
|
|
this->name = xstrdup(name);
|
|
if (strcmp(name, " ") != 0)
|
|
this->score++;
|
|
}
|
|
|
|
void GameInfo::setScreenshot(SDL_Surface *scr)
|
|
{
|
|
SDL_FreeSurface(this->screenshot);
|
|
this->screenshot = scr;
|
|
if (scr != NULL)
|
|
this->score++;
|
|
}
|