Add parser for path
- Adds parser for path - Fix bug: read wrong number of bytes for matrix - Fix bug: checked wrong number of bytes read by fread in many places - Rename _read macros to _decode
This commit is contained in:
parent
8e6234b1be
commit
fd0148ec21
220
src/hvif-light.c
220
src/hvif-light.c
|
@ -80,22 +80,32 @@ struct hvif_matrix
|
||||||
};
|
};
|
||||||
|
|
||||||
/* TODO: This is most likely wrong */
|
/* TODO: This is most likely wrong */
|
||||||
#define ID_TRANSFORMATION \
|
#define MATRIX_ID \
|
||||||
(hvif_matrix) { 1.0, 0.0, 0.0, 0.0, 1.0, 0.0 }
|
(hvif_matrix) { 1.0, 0.0, 0.0, 0.0, 1.0, 0.0 }
|
||||||
|
|
||||||
#define hvif_read(V, BUFFER) \
|
typedef struct hvif_point hvif_point;
|
||||||
|
struct hvif_point
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define POINT_ORIGIN \
|
||||||
|
(hvif_point) { 0.0, 0.0 }
|
||||||
|
|
||||||
|
#define hvif_decode(V, BUFFER) \
|
||||||
V = _Generic((V), uint32_t \
|
V = _Generic((V), uint32_t \
|
||||||
: hvif_read_uint32, float \
|
: hvif_decode_uint32, float \
|
||||||
: hvif_read_float, hvif_matrix \
|
: hvif_decode_float, hvif_matrix \
|
||||||
: hvif_read_hvif_matrix)(BUFFER)
|
: hvif_decode_hvif_matrix)(BUFFER)
|
||||||
static inline uint32_t
|
static inline uint32_t
|
||||||
hvif_read_uint32(char buffer[static 1])
|
hvif_decode_uint32(char buffer[static 1])
|
||||||
{
|
{
|
||||||
return (buffer[0] << 0) | (buffer[1] << 8) | (buffer[2] << 16) |
|
return (buffer[0] << 0) | (buffer[1] << 8) | (buffer[2] << 16) |
|
||||||
(buffer[3] << 24);
|
(buffer[3] << 24);
|
||||||
}
|
}
|
||||||
static inline float
|
static inline float
|
||||||
hvif_read_float(char buffer[static 1])
|
hvif_decode_float(char buffer[static 1])
|
||||||
{
|
{
|
||||||
int shortValue = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];
|
int shortValue = (buffer[0] << 16) | (buffer[1] << 8) | buffer[2];
|
||||||
int sign = (shortValue & 0x800000) >> 23;
|
int sign = (shortValue & 0x800000) >> 23;
|
||||||
|
@ -110,12 +120,13 @@ hvif_read_float(char buffer[static 1])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
static inline hvif_matrix
|
static inline hvif_matrix
|
||||||
hvif_read_hvif_matrix(char buffer[static 1])
|
hvif_decode_hvif_matrix(char buffer[static 1])
|
||||||
{
|
{
|
||||||
return (
|
return (hvif_matrix){
|
||||||
hvif_matrix){ hvif_read_float(buffer), hvif_read_float(&buffer[3]),
|
hvif_decode_float(buffer), hvif_decode_float(&buffer[3]),
|
||||||
hvif_read_float(&buffer[6]), hvif_read_float(&buffer[9]),
|
hvif_decode_float(&buffer[6]), hvif_decode_float(&buffer[9]),
|
||||||
hvif_read_float(&buffer[12]), hvif_read_float(&buffer[15]) };
|
hvif_decode_float(&buffer[12]), hvif_decode_float(&buffer[15])
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef uint32_t hvif_color; /* 8bit each: alpha, blue, green, red */
|
typedef uint32_t hvif_color; /* 8bit each: alpha, blue, green, red */
|
||||||
|
@ -135,18 +146,37 @@ typedef struct hvif_style hvif_style;
|
||||||
struct hvif_style
|
struct hvif_style
|
||||||
{
|
{
|
||||||
signed gradient_type;
|
signed gradient_type;
|
||||||
uint8_t stops;
|
uint8_t num_stops;
|
||||||
hvif_color* colors;
|
hvif_color* colors;
|
||||||
float* offsets;
|
float* offsets;
|
||||||
hvif_matrix transformation;
|
hvif_matrix transformation;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct hvif_path hvif_path;
|
||||||
|
struct hvif_path
|
||||||
|
{
|
||||||
|
uint8_t num_points;
|
||||||
|
bool closed;
|
||||||
|
uint8_t* commands;
|
||||||
|
hvif_point* points;
|
||||||
|
};
|
||||||
|
|
||||||
struct hvif_image
|
struct hvif_image
|
||||||
{
|
{
|
||||||
uint8_t num_styles;
|
uint8_t num_styles;
|
||||||
hvif_style* styles;
|
hvif_style* styles;
|
||||||
|
uint8_t num_paths;
|
||||||
|
hvif_path* paths;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
uint8_t
|
||||||
|
path_command_at(hvif_path* path, uint8_t index)
|
||||||
|
{
|
||||||
|
uint8_t byte = path->commands[index / 4];
|
||||||
|
uint8_t byte_idx = index % 4;
|
||||||
|
return (byte >> (2 * byte_idx)) & 0x03;
|
||||||
|
}
|
||||||
|
|
||||||
hvif_color
|
hvif_color
|
||||||
decode_color(char* buffer, bool gray, bool alpha)
|
decode_color(char* buffer, bool gray, bool alpha)
|
||||||
{
|
{
|
||||||
|
@ -163,7 +193,7 @@ decode_color(char* buffer, bool gray, bool alpha)
|
||||||
COLOR_SET_RGB(c, buffer[0], buffer[0], buffer[0]);
|
COLOR_SET_RGB(c, buffer[0], buffer[0], buffer[0]);
|
||||||
COLOR_SET_ALPHA(c, buffer[1]);
|
COLOR_SET_ALPHA(c, buffer[1]);
|
||||||
} else {
|
} else {
|
||||||
hvif_read(c, buffer);
|
hvif_decode(c, buffer);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
COLOR_SET_ALPHA(c, 0xff);
|
COLOR_SET_ALPHA(c, 0xff);
|
||||||
|
@ -180,6 +210,7 @@ hvif_status
|
||||||
read_color_style(hvif_style* style, char* buffer, bool gray, bool alpha)
|
read_color_style(hvif_style* style, char* buffer, bool gray, bool alpha)
|
||||||
{
|
{
|
||||||
hvif_color color = decode_color(buffer, gray, alpha);
|
hvif_color color = decode_color(buffer, gray, alpha);
|
||||||
|
style->num_stops = 1;
|
||||||
style->colors = calloc(1, sizeof(hvif_color));
|
style->colors = calloc(1, sizeof(hvif_color));
|
||||||
style->offsets = calloc(1, sizeof(float));
|
style->offsets = calloc(1, sizeof(float));
|
||||||
if (!style->colors || !style->colors) return ERROR_NOMEM;
|
if (!style->colors || !style->colors) return ERROR_NOMEM;
|
||||||
|
@ -210,16 +241,19 @@ read_gradient_style(hvif_style* style, FILE* file, char* style_buffer)
|
||||||
if (gradient_flags & GRADIENT_FLAG_TRANSFORM) {
|
if (gradient_flags & GRADIENT_FLAG_TRANSFORM) {
|
||||||
/* The transformation matrix is 6 hvif-floats: 18 bytes */
|
/* The transformation matrix is 6 hvif-floats: 18 bytes */
|
||||||
char buffer[18];
|
char buffer[18];
|
||||||
if (fread(buffer, 1, 2, file) != 2) { return ERROR_EOF; }
|
if (fread(buffer, 1, 18, file) != 18) { return ERROR_EOF; }
|
||||||
hvif_read(transformation, buffer);
|
hvif_decode(transformation, buffer);
|
||||||
} else {
|
} else {
|
||||||
transformation = ID_TRANSFORMATION;
|
transformation = MATRIX_ID;
|
||||||
}
|
}
|
||||||
style->transformation = transformation;
|
style->transformation = transformation;
|
||||||
|
|
||||||
|
style->num_stops = gradient_stops;
|
||||||
style->offsets = calloc(gradient_stops, sizeof(float));
|
style->offsets = calloc(gradient_stops, sizeof(float));
|
||||||
style->colors = calloc(gradient_stops, sizeof(hvif_color));
|
style->colors = calloc(gradient_stops, sizeof(hvif_color));
|
||||||
|
|
||||||
|
if (!style->offsets || !style->colors) return ERROR_NOMEM;
|
||||||
|
|
||||||
char buffer[4];
|
char buffer[4];
|
||||||
for (unsigned i = 0; i < gradient_stops; ++i) {
|
for (unsigned i = 0; i < gradient_stops; ++i) {
|
||||||
if (fread(buffer, 1, 1, file) != 1) { return ERROR_EOF; }
|
if (fread(buffer, 1, 1, file) != 1) { return ERROR_EOF; }
|
||||||
|
@ -230,7 +264,7 @@ read_gradient_style(hvif_style* style, FILE* file, char* style_buffer)
|
||||||
if (fread(buffer, 1, 2, file) != 2) { return ERROR_EOF; }
|
if (fread(buffer, 1, 2, file) != 2) { return ERROR_EOF; }
|
||||||
c = decode_color(buffer, gray, alpha);
|
c = decode_color(buffer, gray, alpha);
|
||||||
} else {
|
} else {
|
||||||
if (fread(buffer, 1, 4, file) != 1) { return ERROR_EOF; }
|
if (fread(buffer, 1, 4, file) != 4) { return ERROR_EOF; }
|
||||||
c = decode_color(buffer, gray, alpha);
|
c = decode_color(buffer, gray, alpha);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -238,7 +272,7 @@ read_gradient_style(hvif_style* style, FILE* file, char* style_buffer)
|
||||||
if (fread(buffer, 1, 1, file) != 1) { return ERROR_EOF; }
|
if (fread(buffer, 1, 1, file) != 1) { return ERROR_EOF; }
|
||||||
c = decode_color(buffer, gray, alpha);
|
c = decode_color(buffer, gray, alpha);
|
||||||
} else {
|
} else {
|
||||||
if (fread(buffer, 1, 3, file) != 1) { return ERROR_EOF; }
|
if (fread(buffer, 1, 3, file) != 3) { return ERROR_EOF; }
|
||||||
c = decode_color(buffer, gray, alpha);
|
c = decode_color(buffer, gray, alpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,7 +287,7 @@ hvif_status
|
||||||
read_style(FILE* file, hvif_style* style)
|
read_style(FILE* file, hvif_style* style)
|
||||||
{
|
{
|
||||||
uint8_t type;
|
uint8_t type;
|
||||||
if (fread(&type, 1, 1, file) != 1) { return ERROR_STYLE; }
|
if (fread(&type, 1, 1, file) != 1) { return ERROR_EOF; }
|
||||||
char buffer[4];
|
char buffer[4];
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case STYLE_TYPE_SOLID_COLOR:
|
case STYLE_TYPE_SOLID_COLOR:
|
||||||
|
@ -281,6 +315,124 @@ read_style(FILE* file, hvif_style* style)
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hvif_status
|
||||||
|
read_coordinate(FILE* file, float* coord)
|
||||||
|
{
|
||||||
|
uint8_t high_value;
|
||||||
|
if (fread(&high_value, 1, 1, file) != 1) { return ERROR_EOF; }
|
||||||
|
|
||||||
|
/* If the highest bit is set, the coordinate uses two bytes */
|
||||||
|
if (high_value & 128) {
|
||||||
|
high_value &= 127;
|
||||||
|
|
||||||
|
uint8_t low_value;
|
||||||
|
if (fread(&low_value, 1, 1, file) != 1) { return ERROR_EOF; }
|
||||||
|
|
||||||
|
uint16_t coord_value = (high_value << 8) | low_value;
|
||||||
|
*coord = ((float)coord_value) / 102.0 - 128.0;
|
||||||
|
} else {
|
||||||
|
*coord = ((float)high_value) - 32.0;
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
hvif_status
|
||||||
|
read_path_points(FILE* file, hvif_path* path)
|
||||||
|
{
|
||||||
|
/* Every path point is three points: the proper point, in point, out point */
|
||||||
|
path->points = calloc(3 * path->num_points, sizeof(hvif_point));
|
||||||
|
if (!path->points) return ERROR_NOMEM;
|
||||||
|
|
||||||
|
hvif_point last = POINT_ORIGIN;
|
||||||
|
hvif_point point;
|
||||||
|
hvif_point point_in;
|
||||||
|
hvif_point point_out;
|
||||||
|
hvif_status status;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < path->num_points; i += 3) {
|
||||||
|
switch (path_command_at(path, i)) {
|
||||||
|
case PATH_COMMAND_H_LINE:
|
||||||
|
point = last;
|
||||||
|
status = read_coordinate(file, &point.x);
|
||||||
|
if (status != SUCCESS) return status;
|
||||||
|
point_in = point_out = point;
|
||||||
|
break;
|
||||||
|
case PATH_COMMAND_V_LINE:
|
||||||
|
point = last;
|
||||||
|
status = read_coordinate(file, &point.x);
|
||||||
|
if (status != SUCCESS) return status;
|
||||||
|
point_in = point_out = point;
|
||||||
|
break;
|
||||||
|
case PATH_COMMAND_LINE:
|
||||||
|
status = read_coordinate(file, &point.x);
|
||||||
|
if (status != SUCCESS) return status;
|
||||||
|
status = read_coordinate(file, &point.y);
|
||||||
|
if (status != SUCCESS) return status;
|
||||||
|
point_in = point_out = point;
|
||||||
|
break;
|
||||||
|
case PATH_COMMAND_CURVE:
|
||||||
|
status = read_coordinate(file, &point.x);
|
||||||
|
if (status != SUCCESS) return status;
|
||||||
|
status = read_coordinate(file, &point.y);
|
||||||
|
if (status != SUCCESS) return status;
|
||||||
|
point_in = point_out = point;
|
||||||
|
status = read_coordinate(file, &point_in.x);
|
||||||
|
if (status != SUCCESS) return status;
|
||||||
|
status = read_coordinate(file, &point_in.y);
|
||||||
|
if (status != SUCCESS) return status;
|
||||||
|
point_in = point_out = point;
|
||||||
|
status = read_coordinate(file, &point_out.x);
|
||||||
|
if (status != SUCCESS) return status;
|
||||||
|
status = read_coordinate(file, &point_out.y);
|
||||||
|
if (status != SUCCESS) return status;
|
||||||
|
point_in = point_out = point;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
path->points[i] = point;
|
||||||
|
path->points[i + 1] = point_in;
|
||||||
|
path->points[i + 2] = point_out;
|
||||||
|
last = point;
|
||||||
|
}
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
create_static_commands(
|
||||||
|
uint8_t num_command_bytes, uint8_t commands[static 1], const uint8_t cmd)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < num_command_bytes; ++i) commands[i] = cmd;
|
||||||
|
}
|
||||||
|
|
||||||
|
hvif_status
|
||||||
|
read_path(FILE* file, hvif_path* path)
|
||||||
|
{
|
||||||
|
uint8_t flags;
|
||||||
|
if (fread(&flags, 1, 1, file) != 1) { return ERROR_PATH; }
|
||||||
|
if (fread(&path->num_points, 1, 1, file) != 1) { return ERROR_PATH; }
|
||||||
|
|
||||||
|
path->closed = flags & PATH_FLAG_CLOSED;
|
||||||
|
uint8_t num_command_bytes = (path->num_points + 3) / 4;
|
||||||
|
path->commands = calloc(num_command_bytes, 1);
|
||||||
|
if (!path->commands) return ERROR_NOMEM;
|
||||||
|
|
||||||
|
if ((flags & PATH_FLAG_USES_COMMANDS) && (flags & PATH_FLAG_NO_CURVES)) {
|
||||||
|
return ERROR_PATH;
|
||||||
|
}
|
||||||
|
if (flags & PATH_FLAG_USES_COMMANDS) {
|
||||||
|
if (fread(&flags, 1, num_command_bytes, file) != num_command_bytes) {
|
||||||
|
return ERROR_PATH;
|
||||||
|
}
|
||||||
|
} else if (flags & PATH_FLAG_NO_CURVES) {
|
||||||
|
create_static_commands(
|
||||||
|
num_command_bytes, path->commands, 0xFF); /* 0b11111111: all curves */
|
||||||
|
} else { /* All lines */
|
||||||
|
create_static_commands(
|
||||||
|
num_command_bytes, path->commands, 0xAA); /* 0b10101010: all lines */
|
||||||
|
}
|
||||||
|
|
||||||
|
return read_path_points(file, path);
|
||||||
|
}
|
||||||
|
|
||||||
hvif_result
|
hvif_result
|
||||||
hvif_from_file(FILE* file)
|
hvif_from_file(FILE* file)
|
||||||
{
|
{
|
||||||
|
@ -289,18 +441,17 @@ hvif_from_file(FILE* file)
|
||||||
char magic_buffer[4];
|
char magic_buffer[4];
|
||||||
if (fread(magic_buffer, 1, 4, file) != 4) { return ERROR_RESULT(ERROR_EOF); }
|
if (fread(magic_buffer, 1, 4, file) != 4) { return ERROR_RESULT(ERROR_EOF); }
|
||||||
uint32_t read_magic;
|
uint32_t read_magic;
|
||||||
hvif_read(read_magic, magic_buffer);
|
hvif_decode(read_magic, magic_buffer);
|
||||||
if (read_magic != magic) { return ERROR_RESULT(ERROR_MAGIC); }
|
if (read_magic != magic) { return ERROR_RESULT(ERROR_MAGIC); }
|
||||||
|
|
||||||
hvif_image* image = calloc(1, sizeof(hvif_image));
|
hvif_image* image = calloc(1, sizeof(hvif_image));
|
||||||
if (!image) return ERROR_RESULT(ERROR_NOMEM);
|
if (!image) return ERROR_RESULT(ERROR_NOMEM);
|
||||||
|
|
||||||
uint8_t num_styles;
|
if (fread(&image->num_styles, 1, 1, file) != 1) {
|
||||||
if (fread(&num_styles, 1, 1, file) != 1) {
|
|
||||||
hvif_free(image);
|
hvif_free(image);
|
||||||
return ERROR_RESULT(ERROR_EOF);
|
return ERROR_RESULT(ERROR_EOF);
|
||||||
}
|
}
|
||||||
image->styles = calloc(num_styles, sizeof(hvif_style));
|
image->styles = calloc(image->num_styles, sizeof(hvif_style));
|
||||||
if (!image->styles) {
|
if (!image->styles) {
|
||||||
hvif_free(image);
|
hvif_free(image);
|
||||||
return ERROR_RESULT(ERROR_NOMEM);
|
return ERROR_RESULT(ERROR_NOMEM);
|
||||||
|
@ -313,6 +464,23 @@ hvif_from_file(FILE* file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fread(&image->num_paths, 1, 1, file) != 1) {
|
||||||
|
hvif_free(image);
|
||||||
|
return ERROR_RESULT(ERROR_EOF);
|
||||||
|
}
|
||||||
|
image->paths = calloc(image->num_paths, sizeof(hvif_path));
|
||||||
|
if (!image->paths) {
|
||||||
|
hvif_free(image);
|
||||||
|
return ERROR_RESULT(ERROR_NOMEM);
|
||||||
|
}
|
||||||
|
for (unsigned i = 0; i < image->num_paths; ++i) {
|
||||||
|
hvif_status s = read_path(file, &image->paths[i]);
|
||||||
|
if (s != SUCCESS) {
|
||||||
|
hvif_free(image);
|
||||||
|
return ERROR_RESULT(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return SUCCESS_RESULT(image);
|
return SUCCESS_RESULT(image);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,6 +491,10 @@ hvif_free(hvif_image* image)
|
||||||
free(image->styles[i].colors);
|
free(image->styles[i].colors);
|
||||||
free(image->styles[i].offsets);
|
free(image->styles[i].offsets);
|
||||||
}
|
}
|
||||||
|
for (unsigned i = 0; i < image->num_paths; ++i) {
|
||||||
|
free(image->paths[i].commands);
|
||||||
|
free(image->paths[i].points);
|
||||||
|
}
|
||||||
free(image->styles);
|
free(image->styles);
|
||||||
free(image);
|
free(image);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,8 @@ typedef enum hvif_status
|
||||||
ERROR_EOF,
|
ERROR_EOF,
|
||||||
ERROR_NOMEM,
|
ERROR_NOMEM,
|
||||||
ERROR_MAGIC,
|
ERROR_MAGIC,
|
||||||
ERROR_STYLE
|
ERROR_STYLE,
|
||||||
|
ERROR_PATH
|
||||||
} hvif_status;
|
} hvif_status;
|
||||||
|
|
||||||
typedef struct hvif_image hvif_image;
|
typedef struct hvif_image hvif_image;
|
||||||
|
|
Loading…
Reference in New Issue