vita-mksfoex.c (6658B)
1 /* 2 # _____ ___ ____ ___ ____ 3 # ____| | ____| | | |____| 4 # | ___| | ___| ____| | \ PSPDEV Open Source Project. 5 #----------------------------------------------------------------------- 6 # Review pspsdk README & LICENSE files for further details. 7 # 8 # New and improved mksfo 9 # $Id$ 10 */ 11 #include <stdio.h> 12 #include <stdint.h> 13 #include <string.h> 14 #include <stdlib.h> 15 #include "getopt.h" 16 #include "types.h" 17 18 #define PSF_MAGIC 0x46535000 19 #define PSF_VERSION 0x00000101 20 21 struct SfoHeader 22 { 23 uint32_t magic; 24 uint32_t version; 25 uint32_t keyofs; 26 uint32_t valofs; 27 uint32_t count; 28 }; 29 30 struct SfoEntry 31 { 32 uint16_t nameofs; 33 uint8_t alignment; 34 uint8_t type; 35 uint32_t valsize; 36 uint32_t totalsize; 37 uint32_t dataofs; 38 }; 39 40 #define PSF_TYPE_BIN 0 41 #define PSF_TYPE_STR 2 42 #define PSF_TYPE_VAL 4 43 44 struct EntryContainer 45 { 46 const char *name; 47 int type; 48 uint32_t value; 49 const char *data; 50 }; 51 52 struct EntryContainer g_defaults[] = { 53 { "APP_VER", PSF_TYPE_STR, 0, "00.00" }, 54 { "ATTRIBUTE", PSF_TYPE_VAL, 0x8000, NULL }, 55 { "ATTRIBUTE2", PSF_TYPE_VAL, 0, NULL }, 56 { "ATTRIBUTE_MINOR", PSF_TYPE_VAL, 0x10, NULL }, 57 { "BOOT_FILE", PSF_TYPE_STR, 32, "" }, 58 { "CATEGORY", PSF_TYPE_STR, 0, "gd" }, 59 { "CONTENT_ID", PSF_TYPE_STR, 48, "" }, 60 { "EBOOT_APP_MEMSIZE", PSF_TYPE_VAL, 0, NULL }, 61 { "EBOOT_ATTRIBUTE", PSF_TYPE_VAL, 0, NULL }, 62 { "EBOOT_PHY_MEMSIZE", PSF_TYPE_VAL, 0, NULL }, 63 { "LAREA_TYPE", PSF_TYPE_VAL, 0, NULL }, 64 { "NP_COMMUNICATION_ID", PSF_TYPE_STR, 16, "" }, 65 { "PARENTAL_LEVEL", PSF_TYPE_VAL, 0, NULL }, 66 { "PSP2_DISP_VER", PSF_TYPE_STR, 0, "00.000" }, 67 { "PSP2_SYSTEM_VER", PSF_TYPE_VAL, 0, NULL }, 68 { "STITLE", PSF_TYPE_STR, 52, "Homebrew" }, 69 { "TITLE", PSF_TYPE_STR, 0x80, "Homebrew" }, 70 { "TITLE_ID", PSF_TYPE_STR, 0, "ABCD99999" }, 71 { "VERSION", PSF_TYPE_STR, 0, "00.00" }, 72 }; 73 74 #define MAX_OPTIONS (256) 75 76 static const char *g_title = NULL; 77 static const char *g_filename = NULL; 78 static int g_empty = 0; 79 static struct EntryContainer g_vals[MAX_OPTIONS]; 80 81 static struct option arg_opts[] = 82 { 83 {"dword", required_argument, NULL, 'd'}, 84 {"string", required_argument, NULL, 's'}, 85 {"empty", no_argument, NULL, 'e'}, 86 { NULL, 0, NULL, 0 } 87 }; 88 89 struct EntryContainer *find_free() 90 { 91 int i; 92 93 for(i = 0; i < MAX_OPTIONS; i++) 94 { 95 if(g_vals[i].name == NULL) 96 { 97 return &g_vals[i]; 98 } 99 } 100 101 return NULL; 102 } 103 104 struct EntryContainer *find_name(const char *name) 105 { 106 int i; 107 108 for(i = 0; i < MAX_OPTIONS; i++) 109 { 110 if((g_vals[i].name != NULL) && (strcmp(g_vals[i].name, name) == 0)) 111 { 112 return &g_vals[i]; 113 } 114 } 115 116 return NULL; 117 } 118 119 int add_string(char *str) 120 { 121 char *equals = NULL; 122 struct EntryContainer *entry; 123 124 equals = strchr(str, '='); 125 if(equals == NULL) 126 { 127 fprintf(stderr, "Invalid option (no =)\n"); 128 return 0; 129 } 130 131 *equals++ = 0; 132 133 if ((entry = find_name(str))) 134 { 135 entry->data = equals; 136 } 137 else 138 { 139 entry = find_free(); 140 if(entry == NULL) 141 { 142 fprintf(stderr, "Maximum options reached\n"); 143 return 0; 144 } 145 146 memset(entry, 0, sizeof(struct EntryContainer)); 147 entry->name = str; 148 entry->type = PSF_TYPE_STR; 149 entry->data = equals; 150 } 151 152 return 1; 153 } 154 155 int add_dword(char *str) 156 { 157 char *equals = NULL; 158 struct EntryContainer *entry; 159 160 equals = strchr(str, '='); 161 if(equals == NULL) 162 { 163 fprintf(stderr, "Invalid option (no =)\n"); 164 return 0; 165 } 166 167 *equals++ = 0; 168 169 if ((entry = find_name(str))) 170 { 171 entry->value = strtoul(equals, NULL, 0); 172 } 173 else 174 { 175 entry = find_free(); 176 if(entry == NULL) 177 { 178 fprintf(stderr, "Maximum options reached\n"); 179 return 0; 180 } 181 182 memset(entry, 0, sizeof(struct EntryContainer)); 183 entry->name = str; 184 entry->type = PSF_TYPE_VAL; 185 entry->value = strtoul(equals, NULL, 0); 186 } 187 188 return 1; 189 } 190 191 /* Process the arguments */ 192 int process_args(int argc, char **argv) 193 { 194 int ch; 195 196 g_title = NULL; 197 g_filename = NULL; 198 g_empty = 0; 199 200 ch = getopt_long(argc, argv, "ed:s:", arg_opts, NULL); 201 while(ch != -1) 202 { 203 switch(ch) 204 { 205 case 'd' : if(!add_dword(optarg)) 206 { 207 return 0; 208 } 209 break; 210 case 's' : if(!add_string(optarg)) 211 { 212 } 213 break; 214 default : break; 215 }; 216 217 ch = getopt_long(argc, argv, "ed:s:", arg_opts, NULL); 218 } 219 220 argc -= optind; 221 argv += optind; 222 223 if(argc < 1) 224 { 225 return 0; 226 } 227 228 if(!g_empty) 229 { 230 g_title = argv[0]; 231 argc--; 232 argv++; 233 } 234 235 if(argc < 1) 236 { 237 return 0; 238 } 239 240 g_filename = argv[0]; 241 242 return 1; 243 } 244 245 int main(int argc, char **argv) 246 { 247 FILE *fp; 248 int i; 249 char head[8192]; 250 char keys[8192]; 251 char data[8192]; 252 struct SfoHeader *h; 253 struct SfoEntry *e; 254 char *k; 255 char *d; 256 unsigned int align; 257 unsigned int keyofs; 258 unsigned int count; 259 260 for(i = 0; i < (sizeof(g_defaults) / sizeof(struct EntryContainer)); i++) 261 { 262 struct EntryContainer *entry = find_free(); 263 if(entry == NULL) 264 { 265 fprintf(stderr, "Maximum options reached\n"); 266 return 0; 267 } 268 *entry = g_defaults[i]; 269 } 270 271 if(!process_args(argc, argv)) 272 { 273 fprintf(stderr, "usage: mksfoex [options] TITLE output.sfo\n"); 274 fprintf(stderr, "\t-d NAME=VALUE Add a new DWORD value\n"); 275 fprintf(stderr, "\t-s NAME=STR Add a new string value\n"); 276 277 return 1; 278 } 279 280 if (g_title) 281 { 282 struct EntryContainer *entry = find_name("TITLE"); 283 entry->data = g_title; 284 285 entry = find_name("STITLE"); 286 entry->data = g_title; 287 } 288 289 memset(head, 0, sizeof(head)); 290 memset(keys, 0, sizeof(keys)); 291 memset(data, 0, sizeof(data)); 292 h = (struct SfoHeader*) head; 293 e = (struct SfoEntry*) (head+sizeof(struct SfoHeader)); 294 k = keys; 295 d = data; 296 SW(&h->magic, PSF_MAGIC); 297 SW(&h->version, PSF_VERSION); 298 count = 0; 299 300 for(i = 0; g_vals[i].name; i++) 301 { 302 SW(&h->count, ++count); 303 SW(&e->nameofs, k-keys); 304 SW(&e->dataofs, d-data); 305 SW(&e->alignment, 4); 306 SW(&e->type, g_vals[i].type); 307 308 strcpy(k, g_vals[i].name); 309 k += strlen(k)+1; 310 if(e->type == PSF_TYPE_VAL) 311 { 312 SW(&e->valsize, 4); 313 SW(&e->totalsize, 4); 314 SW((uint32_t*) d, g_vals[i].value); 315 d += 4; 316 } 317 else 318 { 319 int totalsize; 320 int valsize = 0; 321 322 if (g_vals[i].data) 323 valsize = strlen(g_vals[i].data)+1; 324 totalsize = (g_vals[i].value) ? (g_vals[i].value) : ((valsize + 3) & ~3); 325 SW(&e->valsize, valsize); 326 SW(&e->totalsize, totalsize); 327 memset(d, 0, totalsize); 328 329 if (g_vals[i].data) 330 memcpy(d, g_vals[i].data, valsize); 331 d += totalsize; 332 } 333 e++; 334 } 335 336 337 keyofs = (char*)e - head; 338 SW(&h->keyofs, keyofs); 339 align = 3 - ((unsigned int) (k-keys) & 3); 340 while(align < 3) 341 { 342 k++; 343 align--; 344 } 345 346 SW(&h->valofs, keyofs + (k-keys)); 347 348 fp = fopen(g_filename, "wb"); 349 if(fp == NULL) 350 { 351 fprintf(stderr, "Cannot open filename %s\n", g_filename); 352 return 0; 353 } 354 355 fwrite(head, 1, (char*)e-head, fp); 356 fwrite(keys, 1, k-keys, fp); 357 fwrite(data, 1, d-data, fp); 358 fclose(fp); 359 360 return 0; 361 }