Files
pspsdk/tools/mksfoex.c
2010-10-18 12:54:49 -03:00

342 lines
5.9 KiB
C

/*
# _____ ___ ____ ___ ____
# ____| | ____| | | |____|
# | ___| | ___| ____| | \ PSPDEV Open Source Project.
#-----------------------------------------------------------------------
# Review pspsdk README & LICENSE files for further details.
#
# New and improved mksfo
# $Id$
*/
#include <stdio.h>
#include <stdint.h>
#include <getopt.h>
#include <string.h>
#include <stdlib.h>
#include "types.h"
#define PSF_MAGIC 0x46535000
#define PSF_VERSION 0x00000101
struct SfoHeader
{
uint32_t magic;
uint32_t version;
uint32_t keyofs;
uint32_t valofs;
uint32_t count;
} __attribute__((packed));
struct SfoEntry
{
uint16_t nameofs;
uint8_t alignment;
uint8_t type;
uint32_t valsize;
uint32_t totalsize;
uint32_t dataofs;
} __attribute__((packed));
#define PSF_TYPE_BIN 0
#define PSF_TYPE_STR 2
#define PSF_TYPE_VAL 4
struct EntryContainer
{
const char *name;
int type;
uint32_t value;
const char *data;
};
struct EntryContainer g_defaults[] = {
{ "BOOTABLE", PSF_TYPE_VAL, 1, NULL },
{ "CATEGORY", PSF_TYPE_STR, 0, "MG" },
{ "DISC_ID", PSF_TYPE_STR, 0, "UCJS10041" },
{ "DISC_VERSION", PSF_TYPE_STR, 0, "1.00" },
{ "PARENTAL_LEVEL", PSF_TYPE_VAL, 1, NULL },
{ "PSP_SYSTEM_VER", PSF_TYPE_STR, 0, "1.00" },
{ "REGION", PSF_TYPE_VAL, 0x8000, NULL },
};
#define MAX_OPTIONS (256)
static const char *g_title = NULL;
static const char *g_filename = NULL;
static int g_empty = 0;
static struct EntryContainer g_vals[MAX_OPTIONS];
static struct option arg_opts[] =
{
{"dword", required_argument, NULL, 'd'},
{"string", required_argument, NULL, 's'},
{"empty", no_argument, NULL, 'e'},
{ NULL, 0, NULL, 0 }
};
struct EntryContainer *find_free()
{
int i;
for(i = 0; i < MAX_OPTIONS; i++)
{
if(g_vals[i].name == NULL)
{
return &g_vals[i];
}
}
return NULL;
}
struct EntryContainer *find_name(const char *name)
{
int i;
for(i = 0; i < MAX_OPTIONS; i++)
{
if((g_vals[i].name != NULL) && (strcmp(g_vals[i].name, name) == 0))
{
return &g_vals[i];
}
}
return NULL;
}
int add_string(char *str)
{
char *equals = NULL;
struct EntryContainer *entry;
equals = strchr(str, '=');
if(equals == NULL)
{
fprintf(stderr, "Invalid option (no =)\n");
return 0;
}
*equals++ = 0;
entry = find_free();
if(entry == NULL)
{
fprintf(stderr, "Maximum options reached\n");
return 0;
}
memset(entry, 0, sizeof(struct EntryContainer));
entry->name = str;
entry->type = PSF_TYPE_STR;
entry->data = equals;
return 1;
}
int add_dword(char *str)
{
char *equals = NULL;
struct EntryContainer *entry;
equals = strchr(str, '=');
if(equals == NULL)
{
fprintf(stderr, "Invalid option (no =)\n");
return 0;
}
*equals++ = 0;
entry = find_free();
if(entry == NULL)
{
fprintf(stderr, "Maximum options reached\n");
return 0;
}
memset(entry, 0, sizeof(struct EntryContainer));
entry->name = str;
entry->type = PSF_TYPE_VAL;
entry->value = strtoul(equals, NULL, 0);
return 1;
}
/* Process the arguments */
int process_args(int argc, char **argv)
{
int ch;
g_title = NULL;
g_filename = NULL;
g_empty = 0;
ch = getopt_long(argc, argv, "ed:s:", arg_opts, NULL);
while(ch != -1)
{
switch(ch)
{
case 'd' : if(!add_dword(optarg))
{
return 0;
}
break;
case 's' : if(!add_string(optarg))
{
}
break;
default : break;
};
ch = getopt_long(argc, argv, "ed:s:", arg_opts, NULL);
}
argc -= optind;
argv += optind;
if(argc < 1)
{
return 0;
}
if(!g_empty)
{
g_title = argv[0];
argc--;
argv++;
}
if(argc < 1)
{
return 0;
}
g_filename = argv[0];
return 1;
}
int main(int argc, char **argv)
{
FILE *fp;
int i;
char head[8192];
char keys[8192];
char data[8192];
struct SfoHeader *h;
struct SfoEntry *e;
char *k;
char *d;
unsigned int align;
unsigned int keyofs;
unsigned int count;
if(!process_args(argc, argv))
{
fprintf(stderr, "Usage: mksfoex [options] TITLE output.sfo\n");
fprintf(stderr, "Options:\n");
fprintf(stderr, "-d NAME=VALUE - Add a new DWORD value\n");
fprintf(stderr, "-s NAME=STR - Add a new string value\n");
return 1;
}
if(!g_empty)
{
struct EntryContainer *entry;
for(i = 0; i < (sizeof(g_defaults) / sizeof(struct EntryContainer)); i++)
{
if(!find_name(g_defaults[i].name))
{
entry = find_free();
if(entry == NULL)
{
fprintf(stderr, "Maximum options reached\n");
return 0;
}
*entry = g_defaults[i];
}
}
if(!find_name("TITLE"))
{
entry = find_free();
entry->name = "TITLE";
entry->type = PSF_TYPE_STR;
entry->value = 0;
entry->data = g_title;
}
}
memset(head, 0, sizeof(head));
memset(keys, 0, sizeof(keys));
memset(data, 0, sizeof(data));
h = (struct SfoHeader*) head;
e = (struct SfoEntry*) (head+sizeof(struct SfoHeader));
k = keys;
d = data;
SW(&h->magic, PSF_MAGIC);
SW(&h->version, PSF_VERSION);
count = 0;
for(i = 0; g_vals[i].name; i++)
{
SW(&h->count, ++count);
SW(&e->nameofs, k-keys);
SW(&e->dataofs, d-data);
SW(&e->alignment, 4);
SW(&e->type, g_vals[i].type);
strcpy(k, g_vals[i].name);
k += strlen(k)+1;
if(e->type == PSF_TYPE_VAL)
{
SW(&e->valsize, 4);
SW(&e->totalsize, 4);
SW((uint32_t*) d, g_vals[i].value);
d += 4;
}
else
{
int totalsize;
int valsize;
valsize = strlen(g_vals[i].data)+1;
totalsize = (valsize + 3) & ~3;
SW(&e->valsize, valsize);
SW(&e->totalsize, totalsize);
memset(d, 0, totalsize);
memcpy(d, g_vals[i].data, valsize);
d += totalsize;
}
e++;
}
keyofs = (char*)e - head;
SW(&h->keyofs, keyofs);
align = 3 - ((unsigned int) (k-keys) & 3);
while(align < 3)
{
k++;
align--;
}
SW(&h->valofs, keyofs + (k-keys));
fp = fopen(g_filename, "wb");
if(fp == NULL)
{
fprintf(stderr, "Cannot open filename %s\n", g_filename);
return 0;
}
fwrite(head, 1, (char*)e-head, fp);
fwrite(keys, 1, k-keys, fp);
fwrite(data, 1, d-data, fp);
fclose(fp);
return 0;
}