NCER to json decoding

This commit is contained in:
red031000 2023-07-04 00:40:46 +01:00
parent 649aa24a6f
commit c567e1268e
No known key found for this signature in database
GPG Key ID: D27E50C050AE0CE1
8 changed files with 229 additions and 6 deletions

129
gfx.c
View File

@ -774,6 +774,135 @@ void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr, bool ir, in
fclose(fp);
}
void ReadNtrCell(char *path, struct JsonToCellOptions *options)
{
int fileSize;
unsigned char *data = ReadWholeFile(path, &fileSize);
if (memcmp(data, "RECN", 4) != 0) //NCER
{
FATAL_ERROR("Not a valid NCER cell file.\n");
}
options->labelEnabled = data[0xE] != 1;
if (memcmp(data + 0x10, "KBEC", 4) != 0 ) //KBEC
{
FATAL_ERROR("Not a valid KBEC cell file.\n");
}
options->cellCount = data[0x18] | (data[0x19] << 8);
options->extended = data[0x1A] == 1;
if (!options->extended)
{
FATAL_ERROR("Don't know how to deal with not extended yet, bug red031000.\n");
}
options->mappingType = data[0x20];
options->cells = malloc(sizeof(struct Cell *) * options->cellCount);
for (int i = 0; i < options->cellCount; i++)
{
int offset = 0x30 + (i * 0x10);
options->cells[i] = malloc(sizeof(struct Cell));
short cellAttrs = data[offset + 2] | (data[offset + 3] << 8);
options->cells[i]->attributes.hFlip = (cellAttrs >> 8) & 1;
options->cells[i]->attributes.vFlip = (cellAttrs >> 9) & 1;
options->cells[i]->attributes.hvFlip = (cellAttrs >> 10) & 1;
options->cells[i]->attributes.boundingRect = (cellAttrs >> 11) & 1;
options->cells[i]->attributes.boundingSphereRadius = cellAttrs & 0x3F;
options->cells[i]->maxX = data[offset + 8] | (data[offset + 9] << 8);
options->cells[i]->maxY = data[offset + 10] | (data[offset + 11] << 8);
options->cells[i]->minX = data[offset + 12] | (data[offset + 13] << 8);
options->cells[i]->minY = data[offset + 14] | (data[offset + 15] << 8);
}
for (int i = 0; i < options->cellCount; i++)
{
int offset = 0x30 + (options->cellCount * 0x10) + (i * 0x6);
//Attr0
//bits 0-7 Y coordinate
options->cells[i]->oam.attr0.YCoordinate = data[offset];
//bit 8 rotation
options->cells[i]->oam.attr0.Rotation = data[offset + 1] & 1;
//bit 9 Obj Size (if rotation) or Obj Disable (if not rotation)
options->cells[i]->oam.attr0.SizeDisable = (data[offset + 1] >> 1) & 1;
//bits 10-11 Obj Mode
options->cells[i]->oam.attr0.Mode = (data[offset + 1] >> 2) & 3;
//bit 12 Obj Mosaic
options->cells[i]->oam.attr0.Mosaic = (data[offset + 1] >> 4) & 1;
//bit 13 Colours
options->cells[i]->oam.attr0.Colours = ((data[offset + 1] >> 5) & 1) == 0 ? 16 : 256;
//bits 14-15 Obj Shape
options->cells[i]->oam.attr0.Shape = (data[offset + 1] >> 6) & 3;
//Attr1
//bits 0-8 X coordinate
options->cells[i]->oam.attr1.XCoordinate = data[offset + 2] | ((data[offset + 3] & 1) << 8);
//bits 9-13 Rotation and scaling (if rotation) bit 12 Horizontal flip, bit 13 Vertical flip (if not rotation)
options->cells[i]->oam.attr1.RotationScaling = (data[offset + 3] >> 1) & 0x1F;
//bits 14-15 Obj Size
options->cells[i]->oam.attr1.Size = (data[offset + 3] >> 6) & 3;
//Attr2
//bits 0-9 Character Name?
options->cells[i]->oam.attr2.CharName = data[offset + 4] | ((data[offset + 5] & 3) << 8);
//bits 10-11 Priority
options->cells[i]->oam.attr2.Priority = (data[offset + 5] >> 2) & 3;
//bits 12-15 Palette Number
options->cells[i]->oam.attr2.Palette = (data[offset + 5] >> 4) & 0xF;
}
if (options->labelEnabled)
{
int count = 0;
int offset = 0x30 + (options->cellCount * 0x16) + 0x8;
bool flag = false;
//this entire thing is a huge assumption, it will not work with labels that are less than 2 characters long
while (!flag)
{
if (strlen((char *) data + offset) < 2)
{
//probably a pointer, maybe?
count++;
offset += 4;
}
else
{
//huzzah a string
flag = true;
}
}
options->labelCount = count;
options->labels = malloc(sizeof(char *) * count);
for (int i = 0; i < count; i++)
{
options->labels[i] = malloc(strlen((char *) data + offset) + 1);
strcpy(options->labels[i], (char *) data + offset);
offset += strlen(options->labels[i]) + 1;
}
//after this should be txeu, if everything was done right
}
free(data);
}
void WriteNtrCell(char *path, struct JsonToCellOptions *options)
{
FILE *fp = fopen(path, "wb");

1
gfx.h
View File

@ -40,6 +40,7 @@ void ReadGbaPalette(char *path, struct Palette *palette);
void ReadNtrPalette(char *path, struct Palette *palette, int bitdepth, int palIndex);
void WriteGbaPalette(char *path, struct Palette *palette);
void WriteNtrPalette(char *path, struct Palette *palette, bool ncpr, bool ir, int bitdepth, bool pad, int compNum);
void ReadNtrCell(char *path, struct JsonToCellOptions *options);
void WriteNtrCell(char *path, struct JsonToCellOptions *options);
void WriteNtrScreen(char *path, struct JsonToScreenOptions *options);
void WriteNtrAnimation(char *path, struct JsonToAnimationOptions *options);

74
json.c
View File

@ -48,15 +48,11 @@ struct JsonToCellOptions *ParseNCERJson(char *path)
cJSON *labelBool = cJSON_GetObjectItemCaseSensitive(json, "labelEnabled");
cJSON *extended = cJSON_GetObjectItemCaseSensitive(json, "extended");
cJSON *imageHeight = cJSON_GetObjectItemCaseSensitive(json, "imageHeight");
cJSON *imageWidth = cJSON_GetObjectItemCaseSensitive(json, "imageWidth");
cJSON *cellCount = cJSON_GetObjectItemCaseSensitive(json, "cellCount");
cJSON *mappingType = cJSON_GetObjectItemCaseSensitive(json, "mappingType");
options->labelEnabled = GetBool(labelBool);
options->extended = GetBool(extended);
options->imageHeight = GetInt(imageHeight);
options->imageWidth = GetInt(imageWidth);
options->cellCount = GetInt(cellCount);
options->mappingType = GetInt(mappingType);
@ -177,6 +173,76 @@ struct JsonToCellOptions *ParseNCERJson(char *path)
return options;
}
char *GetNCERJson(struct JsonToCellOptions *options)
{
cJSON *ncer = cJSON_CreateObject();
cJSON_AddBoolToObject(ncer, "labelEnabled", options->labelEnabled);
cJSON_AddBoolToObject(ncer, "extended", options->extended);
cJSON_AddNumberToObject(ncer, "cellCount", options->cellCount);
cJSON_AddNumberToObject(ncer, "mappingType", options->mappingType);
cJSON *cells = cJSON_AddArrayToObject(ncer, "cells");
for (int i = 0; i < options->cellCount; i++)
{
cJSON *cell = cJSON_CreateObject();
cJSON *cellAttrs = cJSON_AddObjectToObject(cell, "cellAttrs");
cJSON_AddBoolToObject(cellAttrs, "hFlip", options->cells[i]->attributes.hFlip);
cJSON_AddBoolToObject(cellAttrs, "vFlip", options->cells[i]->attributes.vFlip);
cJSON_AddBoolToObject(cellAttrs, "hvFlip", options->cells[i]->attributes.hvFlip);
cJSON_AddBoolToObject(cellAttrs, "boundingRect", options->cells[i]->attributes.boundingRect);
cJSON_AddNumberToObject(cellAttrs, "boundingSphereRadius", options->cells[i]->attributes.boundingSphereRadius);
if (options->extended)
{
cJSON_AddNumberToObject(cell, "maxX", options->cells[i]->maxX);
cJSON_AddNumberToObject(cell, "maxY", options->cells[i]->maxY);
cJSON_AddNumberToObject(cell, "minX", options->cells[i]->minX);
cJSON_AddNumberToObject(cell, "minY", options->cells[i]->minY);
}
cJSON *OAM = cJSON_AddObjectToObject(cell, "OAM");
cJSON *Attr0 = cJSON_AddObjectToObject(OAM, "Attr0");
cJSON_AddNumberToObject(Attr0, "YCoordinate", options->cells[i]->oam.attr0.YCoordinate);
cJSON_AddBoolToObject(Attr0, "Rotation", options->cells[i]->oam.attr0.Rotation);
cJSON_AddBoolToObject(Attr0, "SizeDisable", options->cells[i]->oam.attr0.SizeDisable);
cJSON_AddNumberToObject(Attr0, "Mode", options->cells[i]->oam.attr0.Mode);
cJSON_AddBoolToObject(Attr0, "Mosaic", options->cells[i]->oam.attr0.Mosaic);
cJSON_AddNumberToObject(Attr0, "Colours", options->cells[i]->oam.attr0.Colours);
cJSON_AddNumberToObject(Attr0, "Shape", options->cells[i]->oam.attr0.Shape);
cJSON *Attr1 = cJSON_AddObjectToObject(OAM, "Attr1");
cJSON_AddNumberToObject(Attr1, "XCoordinate", options->cells[i]->oam.attr1.XCoordinate);
cJSON_AddNumberToObject(Attr1, "RotationScaling", options->cells[i]->oam.attr1.RotationScaling);
cJSON_AddNumberToObject(Attr1, "Size", options->cells[i]->oam.attr1.Size);
cJSON *Attr2 = cJSON_AddObjectToObject(OAM, "Attr2");
cJSON_AddNumberToObject(Attr2, "CharName", options->cells[i]->oam.attr2.CharName);
cJSON_AddNumberToObject(Attr2, "Priority", options->cells[i]->oam.attr2.Priority);
cJSON_AddNumberToObject(Attr2, "Palette", options->cells[i]->oam.attr2.Palette);
cJSON_AddItemToArray(cells, cell);
}
if (options->labelEnabled)
{
cJSON *labels = cJSON_CreateStringArray((const char * const*)options->labels, options->labelCount);
cJSON_AddItemToObject(ncer, "labels", labels);
cJSON_AddNumberToObject(ncer, "labelCount", options->labelCount);
}
char *jsonString = cJSON_Print(ncer);
cJSON_Delete(ncer);
return jsonString;
}
struct JsonToScreenOptions *ParseNSCRJson(char *path)
{
int fileLength;

1
json.h
View File

@ -6,6 +6,7 @@
#include "options.h"
struct JsonToCellOptions *ParseNCERJson(char *path);
char *GetNCERJson(struct JsonToCellOptions *options);
struct JsonToScreenOptions *ParseNSCRJson(char *path);
struct JsonToAnimationOptions *ParseNANRJson(char *path);
void FreeNCERCell(struct JsonToCellOptions *options);

14
main.c
View File

@ -768,6 +768,19 @@ void HandleJsonToNtrCellCommand(char *inputPath, char *outputPath, int argc UNUS
FreeNCERCell(options);
}
void HandleNtrCellToJsonCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
struct JsonToCellOptions *options = malloc(sizeof(struct JsonToCellOptions));
ReadNtrCell(inputPath, options);
char *json = GetNCERJson(options);
WriteWholeStringToFile(outputPath, json);
FreeNCERCell(options);
}
void HandleJsonToNtrScreenCommand(char *inputPath, char *outputPath, int argc UNUSED, char **argv UNUSED)
{
struct JsonToScreenOptions *options;
@ -1094,6 +1107,7 @@ int main(int argc, char **argv)
{ "fwjpnfont", "png", HandleFullwidthJapaneseFontToPngCommand },
{ "png", "fwjpnfont", HandlePngToFullwidthJapaneseFontCommand },
{ "json", "NCER", HandleJsonToNtrCellCommand },
{ "NCER", "json", HandleNtrCellToJsonCommand },
{ "json", "NSCR", HandleJsonToNtrScreenCommand },
{ "json", "NANR", HandleJsonToNtrAnimationCommand },
{ "json", "NMAR", HandleJsonToNtrMulticellAnimationCommand },

View File

@ -98,8 +98,6 @@ struct JsonToCellOptions {
bool labelEnabled;
bool extended;
int mappingType;
int imageHeight;
int imageWidth;
int cellCount;
struct Cell **cells;
char **labels;

13
util.c
View File

@ -111,6 +111,19 @@ unsigned char *ReadWholeFileZeroPadded(char *path, int *size, int padAmount)
return buffer;
}
void WriteWholeStringToFile(char *path, char *string)
{
FILE *fp = fopen(path, "wb");
if (fp == NULL)
FATAL_ERROR("Failed to open \"%s\" for writing.\n", path);
if (fputs(string, fp) == EOF)
FATAL_ERROR("Failed to write to \"%s\".\n", path);
fclose(fp);
}
void WriteWholeFile(char *path, void *buffer, int bufferSize)
{
FILE *fp = fopen(path, "wb");

1
util.h
View File

@ -10,6 +10,7 @@ bool ParseNumber(char *s, char **end, int radix, int *intValue);
char *GetFileExtension(char *path);
unsigned char *ReadWholeFile(char *path, int *size);
unsigned char *ReadWholeFileZeroPadded(char *path, int *size, int padAmount);
void WriteWholeStringToFile(char *path, char *string);
void WriteWholeFile(char *path, void *buffer, int bufferSize);
void WriteGenericNtrHeader(FILE* fp, const char* magicNumber, uint32_t size, bool byteorder, bool version101, uint16_t sectionCount);