Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor of JASC-PAL #620

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
175 changes: 65 additions & 110 deletions tools/gbagfx/jasc_pal.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,155 +2,110 @@

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "global.h"
#include "gfx.h"
#include "util.h"

// Read/write Paint Shop Pro palette files.
// Read/write JASC palette files.

// Format of a Paint Shop Pro palette file, line by line:
// "JASC-PAL\r\n" (signature)
// "0100\r\n" (version; seems to always be "0100")
// "<NUMBER_OF_COLORS>\r\n" (number of colors in decimal)
// Format of a JASC palette file, line by line:
// "JASC-PAL" (signature)
// "0100" (version; seems to always be "0100")
// "<NUMBER_OF_COLORS>" (number of colors in decimal)
//
// <NUMBER_OF_COLORS> times:
// "<RED> <GREEN> <BLUE>\r\n" (color entry)
// "<RED> <GREEN> <BLUE> <ALPHA (discarded if present)>" (color entry)
//
// Line endings can be \r\n or \n
//
// Each color component is a decimal number from 0 to 255.
// Examples:
// Black - "0 0 0\r\n"
// Blue - "0 0 255\r\n"
// Brown - "150 75 0\r\n"
// Black - "0 0 0"
// Blue - "0 0 255"
// Brown - "150 75 0"
// White - "255 255 255 255"
// ^~~ ignored

#define MAX_LINE_LENGTH 11
// 15 chars of color info, \r\n or \n, and \0
#define MAX_LINE_LENGTH 18

void ReadJascPaletteLine(FILE *fp, char *line)
int ReadJascPaletteLine(FILE *fp, char *line)
{
int c;
int length = 0;

for (;;)
{
c = fgetc(fp);

if (c == '\r')
{
c = fgetc(fp);

if (c != '\n')
FATAL_ERROR("CR line endings aren't supported.\n");

line[length] = 0;

return;
}

if (c == '\n')
FATAL_ERROR("LF line endings aren't supported.\n");

if (c == EOF)
FATAL_ERROR("Unexpected EOF. No CRLF at end of file.\n");
int end = 0;

if (c == 0)
FATAL_ERROR("NUL character in file.\n");
// Read line up to first newline char (inclusive) or [MAX_LINE_LENGTH-1]
if(fgets(line, MAX_LINE_LENGTH, fp) == NULL)
return 0;

if (length == MAX_LINE_LENGTH)
{
line[length] = 0;
FATAL_ERROR("The line \"%s\" is too long.\n", line);
}
end = strcspn(line, "\r\n"); // Find index of first newline.

line[length++] = c;
// Max length of 4-channel colour is 15 chars, so max length of resulting
// string should be 16 including \0. If end-of-line is > 15, there's a chance
// we've left newline chars unread for the next line, so we should error out
if (end > MAX_LINE_LENGTH -3) {
FATAL_ERROR("Line is too long: %s\n", line);
} else {
line[end] = 0; // Terminate the line at the first newline char
}
return 1;
}

void ReadJascPalette(char *path, struct Palette *palette)
{
char line[MAX_LINE_LENGTH + 1];
char line_buffer[MAX_LINE_LENGTH];
int red, green, blue;
int numColors;

FILE *fp = fopen(path, "rb");
FILE *fp = fopen(path, "r");

if (fp == NULL)
FATAL_ERROR("Failed to open JASC-PAL file \"%s\" for reading.\n", path);
if (!fp)
FATAL_ERROR("Cannot open JASC-PAL file \"%s\" with error: %s\n", path, strerror(errno));

ReadJascPaletteLine(fp, line);
// Check JASC-PAL Header
if (ReadJascPaletteLine(fp, line_buffer) == 0)
FATAL_ERROR("Failed to read JASC-PAL header.\n");
if (strcmp(line_buffer, "JASC-PAL") != 0)
FATAL_ERROR("Invalid signature, expected \"JASC-PAL\", read: \"%s\"\n",line_buffer);

if (strcmp(line, "JASC-PAL") != 0)
FATAL_ERROR("Invalid JASC-PAL signature.\n");

ReadJascPaletteLine(fp, line);

if (strcmp(line, "0100") != 0)
if (ReadJascPaletteLine(fp, line_buffer) == 0)
FATAL_ERROR("Failed to read version.\n");
if (strcmp(line_buffer, "0100") != 0)
FATAL_ERROR("Unsuported JASC-PAL version.\n");

ReadJascPaletteLine(fp, line);

if (!ParseNumber(line, NULL, 10, &palette->numColors))
FATAL_ERROR("Failed to parse number of colors.\n");

if (palette->numColors < 1 || palette->numColors > 256)
FATAL_ERROR("%d is an invalid number of colors. The number of colors must be in the range [1, 256].\n", palette->numColors);
// Get number of colors in palette
if (ReadJascPaletteLine(fp, line_buffer) == 0)
FATAL_ERROR("Failed to read number of colors.\n");
if (strlen(line_buffer) > 3 || !ParseNumber(line_buffer, NULL, 10, &numColors))
FATAL_ERROR("Failed to parse number of colours.\n");

for (int i = 0; i < palette->numColors; i++)
// Check for sensible number of colors
if (numColors > 0 && numColors <= 256)
{
ReadJascPaletteLine(fp, line);

char *s = line;
char *end;

int red;
int green;
int blue;

if (!ParseNumber(s, &end, 10, &red))
FATAL_ERROR("Failed to parse red color component.\n");

s = end;

if (*s != ' ')
FATAL_ERROR("Expected a space after red color component.\n");

s++;

if (*s < '0' || *s > '9')
FATAL_ERROR("Expected only a space between red and green color components.\n");

if (!ParseNumber(s, &end, 10, &green))
FATAL_ERROR("Failed to parse green color component.\n");

s = end;

if (*s != ' ')
FATAL_ERROR("Expected a space after green color component.\n");

s++;

if (*s < '0' || *s > '9')
FATAL_ERROR("Expected only a space between green and blue color components.\n");

if (!ParseNumber(s, &end, 10, &blue))
FATAL_ERROR("Failed to parse blue color component.\n");
palette->numColors = numColors;
} else {
FATAL_ERROR("%i is an invalid number of colours. The number of colours must be in the range [1, 256]\n", numColors);
}

if (*end != 0)
FATAL_ERROR("Garbage after blue color component.\n");
// Get color entries
for (int i = 0; i < numColors; ++i)
{
if (ReadJascPaletteLine(fp, line_buffer) == 0)
FATAL_ERROR("Failed to read color index %i\n", i);
if (sscanf(line_buffer, "%d %d %d", &red, &green, &blue) != 3)
FATAL_ERROR("Invalid color format in color \"%s\"\n", line_buffer);
waterwheels marked this conversation as resolved.
Show resolved Hide resolved

if (red < 0 || red > 255)
FATAL_ERROR("Red color component (%d) is outside the range [0, 255].\n", red);

FATAL_ERROR("Red color component %d is invalid. Accepted range is [0, 255]\n", red);
if (green < 0 || green > 255)
FATAL_ERROR("Green color component (%d) is outside the range [0, 255].\n", green);

FATAL_ERROR("Green color component %d is invalid. Accepted range is [0, 255]\n", green);
if (blue < 0 || blue > 255)
FATAL_ERROR("Blue color component (%d) is outside the range [0, 255].\n", blue);
FATAL_ERROR("Blue color component %d is invalid. Accepted range is [0, 255]\n", blue);

palette->colors[i].red = red;
palette->colors[i].green = green;
palette->colors[i].blue = blue;
}

if (fgetc(fp) != EOF)
FATAL_ERROR("Garbage after color data.\n");

fclose(fp);
}

Expand Down