mirror of
https://github.com/Relintai/pandemonium_engine.git
synced 2025-04-27 09:44:58 +02:00
334 lines
8.7 KiB
C++
334 lines
8.7 KiB
C++
/**************************************************************************/
|
|
/* vita-mksfoex.cpp */
|
|
/**************************************************************************/
|
|
/* This file is part of: */
|
|
/* GODOT ENGINE */
|
|
/* https://godotengine.org */
|
|
/**************************************************************************/
|
|
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
|
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
|
/* */
|
|
/* Permission is hereby granted, free of charge, to any person obtaining */
|
|
/* a copy of this software and associated documentation files (the */
|
|
/* "Software"), to deal in the Software without restriction, including */
|
|
/* without limitation the rights to use, copy, modify, merge, publish, */
|
|
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
|
/* permit persons to whom the Software is furnished to do so, subject to */
|
|
/* the following conditions: */
|
|
/* */
|
|
/* The above copyright notice and this permission notice shall be */
|
|
/* included in all copies or substantial portions of the Software. */
|
|
/* */
|
|
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
|
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
|
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
|
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
|
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
|
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
|
/**************************************************************************/
|
|
|
|
/*
|
|
# _____ ___ ____ ___ ____
|
|
# ____| | ____| | | |____|
|
|
# | ___| | ___| ____| | \ PSPDEV Open Source Project.
|
|
#-----------------------------------------------------------------------
|
|
# Review pspsdk README & LICENSE files for further details.
|
|
#
|
|
# New and improved mksfo
|
|
# $Id$
|
|
*/
|
|
#define _CRT_SECURE_NO_DEPRECATE
|
|
|
|
#include "export.h"
|
|
#include "types.h"
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.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;
|
|
};
|
|
|
|
struct SfoEntry {
|
|
uint16_t nameofs;
|
|
uint8_t alignment;
|
|
uint8_t type;
|
|
uint32_t valsize;
|
|
uint32_t totalsize;
|
|
uint32_t dataofs;
|
|
};
|
|
|
|
#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[] = {
|
|
{ "APP_VER", PSF_TYPE_STR, 0, "00.00" },
|
|
{ "ATTRIBUTE", PSF_TYPE_VAL, 0x8000, NULL },
|
|
{ "ATTRIBUTE2", PSF_TYPE_VAL, 0, NULL },
|
|
{ "ATTRIBUTE_MINOR", PSF_TYPE_VAL, 0x10, NULL },
|
|
{ "BOOT_FILE", PSF_TYPE_STR, 32, "" },
|
|
{ "CATEGORY", PSF_TYPE_STR, 0, "gd" },
|
|
{ "CONTENT_ID", PSF_TYPE_STR, 48, "" },
|
|
{ "EBOOT_APP_MEMSIZE", PSF_TYPE_VAL, 0, NULL },
|
|
{ "EBOOT_ATTRIBUTE", PSF_TYPE_VAL, 0, NULL },
|
|
{ "EBOOT_PHY_MEMSIZE", PSF_TYPE_VAL, 0, NULL },
|
|
{ "LAREA_TYPE", PSF_TYPE_VAL, 0, NULL },
|
|
{ "NP_COMMUNICATION_ID", PSF_TYPE_STR, 16, "" },
|
|
{ "PARENTAL_LEVEL", PSF_TYPE_VAL, 0, NULL },
|
|
{ "PSP2_DISP_VER", PSF_TYPE_STR, 0, "00.000" },
|
|
{ "PSP2_SYSTEM_VER", PSF_TYPE_VAL, 0, NULL },
|
|
{ "STITLE", PSF_TYPE_STR, 52, "Homebrew" },
|
|
{ "TITLE", PSF_TYPE_STR, 0x80, "Homebrew" },
|
|
{ "TITLE_ID", PSF_TYPE_STR, 0, "ABCD99999" },
|
|
{ "VERSION", PSF_TYPE_STR, 0, "00.00" },
|
|
};
|
|
|
|
#define MAX_OPTIONS (256)
|
|
|
|
static const char *g_title = NULL;
|
|
static int g_empty = 0;
|
|
static struct EntryContainer g_vals[MAX_OPTIONS];
|
|
|
|
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;
|
|
|
|
if ((entry = find_name(str))) {
|
|
entry->data = equals;
|
|
} else {
|
|
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;
|
|
|
|
if ((entry = find_name(str))) {
|
|
entry->value = strtoul(equals, NULL, 0);
|
|
} else {
|
|
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;
|
|
}
|
|
|
|
int mksfoex(ParamSFOStruct *sfo, String outDir) {
|
|
FILE *fp;
|
|
unsigned int i;
|
|
char head[8192];
|
|
char keys[8192];
|
|
char data[8192];
|
|
char title_id[256];
|
|
char version[256];
|
|
char title[256];
|
|
struct SfoHeader *h;
|
|
struct SfoEntry *e;
|
|
char *k;
|
|
char *d;
|
|
unsigned int align;
|
|
unsigned int keyofs;
|
|
unsigned int count;
|
|
|
|
struct EntryContainer *entry;
|
|
|
|
g_empty = 0;
|
|
memset(g_vals, 0, sizeof(EntryContainer) * MAX_OPTIONS);
|
|
memset(title_id, 0, sizeof(title_id));
|
|
memset(version, 0, sizeof(version));
|
|
memset(title, 0, sizeof(title));
|
|
for (i = 0; i < (sizeof(g_defaults) / sizeof(struct EntryContainer)); i++) {
|
|
entry = find_free();
|
|
if (entry == NULL) {
|
|
fprintf(stderr, "Maximum options reached\n");
|
|
return 0;
|
|
}
|
|
*entry = g_defaults[i];
|
|
}
|
|
|
|
if ((entry = find_name("TITLE_ID"))) {
|
|
if (sfo->title_id.length() != 9) {
|
|
fprintf(stderr, "TITLE_ID must be 9 characters long\n");
|
|
return 1;
|
|
}
|
|
strcpy(title_id, sfo->title_id.to_upper().utf8().get_data());
|
|
entry->data = title_id;
|
|
}
|
|
|
|
if ((entry = find_name("VERSION"))) {
|
|
if (sfo->version.length() != 5 || sfo->version.find_char('.') != 2) {
|
|
entry->data = "01.00"; // Default to 01.00 if invalid version
|
|
} else {
|
|
strcpy(version, sfo->version.utf8().get_data());
|
|
entry->data = version;
|
|
}
|
|
}
|
|
|
|
if ((entry = find_name("PARENTAL_LEVEL"))) {
|
|
if (sfo->parental_level < 0 || sfo->parental_level > 11) {
|
|
entry->value = 0;
|
|
} else {
|
|
entry->value = sfo->parental_level;
|
|
}
|
|
}
|
|
|
|
if (sfo->title.length() > 0) {
|
|
strcpy(title, sfo->title.utf8().get_data());
|
|
g_title = title;
|
|
}
|
|
|
|
if (g_title) {
|
|
entry = find_name("TITLE");
|
|
entry->data = g_title;
|
|
entry = find_name("STITLE");
|
|
entry->data = g_title;
|
|
}
|
|
|
|
entry = find_name("ATTRIBUTE2");
|
|
entry->value = 12;
|
|
|
|
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 = 0;
|
|
|
|
if (g_vals[i].data)
|
|
valsize = strlen(g_vals[i].data) + 1;
|
|
totalsize = (g_vals[i].value) ? (g_vals[i].value) : ((valsize + 3) & ~3);
|
|
SW(&e->valsize, valsize);
|
|
SW(&e->totalsize, totalsize);
|
|
memset(d, 0, totalsize);
|
|
|
|
if (g_vals[i].data)
|
|
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));
|
|
|
|
String output = outDir + "/param.sfo";
|
|
fp = fopen(output.utf8().get_data(), "wb");
|
|
if (fp == NULL) {
|
|
fprintf(stderr, "Cannot open filename %s\n", output.utf8().get_data());
|
|
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;
|
|
}
|