Skip to content

Commit

Permalink
Cleanup and better safety checks, 10
Browse files Browse the repository at this point in the history
  • Loading branch information
aaaaaa123456789 committed Jan 25, 2022
1 parent e10cee6 commit ec181e7
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 93 deletions.
22 changes: 6 additions & 16 deletions src/pngwrite.c
Original file line number Diff line number Diff line change
Expand Up @@ -243,28 +243,18 @@ void generate_PNG_row_data (struct context * context, const void * restrict data
case 4: case 5: {
uint32_t * pixels = ctxmalloc(context, sizeof *pixels * context -> source -> width);
plum_convert_colors(pixels, data, context -> source -> width, PLUM_COLOR_32 | PLUM_ALPHA_INVERT, context -> source -> color_format);
for (p = 0; p < context -> source -> width; p ++) {
*(output ++) = pixels[p];
*(output ++) = pixels[p] >> 8;
*(output ++) = pixels[p] >> 16;
if (type == 5) *(output ++) = pixels[p] >> 24;
}
if (type == 5)
for (p = 0; p < context -> source -> width; p ++) write_le32_unaligned(output + 4 * p, pixels[p]);
else
for (p = 0; p < context -> source -> width; p ++) output += byteappend(output, pixels[p], pixels[p] >> 8, pixels[p] >> 16);
ctxfree(context, pixels);
} break;
case 6: case 7: {
uint64_t * pixels = ctxmalloc(context, sizeof *pixels * context -> source -> width);
plum_convert_colors(pixels, data, context -> source -> width, PLUM_COLOR_64 | PLUM_ALPHA_INVERT, context -> source -> color_format);
for (p = 0; p < context -> source -> width; p ++) {
*(output ++) = pixels[p] >> 8;
*(output ++) = pixels[p];
*(output ++) = pixels[p] >> 24;
*(output ++) = pixels[p] >> 16;
*(output ++) = pixels[p] >> 40;
*(output ++) = pixels[p] >> 32;
if (type == 7) {
*(output ++) = pixels[p] >> 56;
*(output ++) = pixels[p] >> 48;
}
output += byteappend(output, pixels[p] >> 8, pixels[p], pixels[p] >> 24, pixels[p] >> 16, pixels[p] >> 40, pixels[p] >> 32);
if (type == 7) output += byteappend(output, pixels[p] >> 56, pixels[p] >> 48);
}
ctxfree(context, pixels);
}
Expand Down
37 changes: 23 additions & 14 deletions src/pnmread.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,17 +56,17 @@ void load_PNM_header (struct context * context, size_t offset, struct PNM_image_
if (header -> type == 6) header -> datalength *= 3;
break;
case 4:
header -> datalength = (size_t) (((header -> width - 1) >> 3) + 1) * header -> height;
header -> datalength = (size_t) ((header -> width - 1) / 8 + 1) * header -> height;
break;
default:
header -> datalength = context -> size - offset;
if (header -> datalength < (header -> type[(const size_t []) {1, 1, 2, 6}] * header -> width * header -> height - 1))
if (((header -> datalength + 1) / header -> type[(const size_t []) {1, 1, 2, 6}]) < ((size_t) header -> width * header -> height))
throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
}
}

void load_PAM_header (struct context * context, size_t offset, struct PNM_image_header * restrict header) {
unsigned fields = 15; // bits 0-3: width, height, max, depth
unsigned fields = 15; // bits 0-3: width, height, max, depth (bit set indicates the field hasn't been read yet)
uint32_t value, depth;
while (1) {
skip_PNM_line(context, &offset);
Expand Down Expand Up @@ -150,11 +150,12 @@ void skip_PNM_whitespace (struct context * context, size_t * restrict offset) {

void skip_PNM_line (struct context * context, size_t * restrict offset) {
int comment;
for (comment = 0; (*offset < context -> size) && (context -> data[*offset] != 10); ++ *offset) if (!comment)
if (context -> data[*offset] == 0x23) // '#'
comment = 1;
else if (!is_whitespace(context -> data[*offset]))
throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
for (comment = 0; (*offset < context -> size) && (context -> data[*offset] != 10); ++ *offset)
if (!comment)
if (context -> data[*offset] == 0x23) // '#'
comment = 1;
else if (!is_whitespace(context -> data[*offset]))
throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
if (*offset < context -> size) ++ *offset;
}

Expand All @@ -168,8 +169,8 @@ unsigned next_PNM_token_length (struct context * context, size_t offset) {
void read_PNM_numbers (struct context * context, size_t * restrict offset, uint32_t * restrict result, size_t count) {
while (count --) {
skip_PNM_whitespace(context, offset);
uint64_t current = 0; // 64-bit so it can catch overflows
if ((*offset >= context -> size) || (context -> data[*offset] < 0x30) || (context -> data[*offset] > 0x39)) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
uint64_t current = context -> data[(*offset) ++] - 0x30; // 64-bit so it can catch overflows
while ((*offset < context -> size) && (context -> data[*offset] >= 0x30) && (context -> data[*offset] <= 0x39)) {
current = current * 10 + context -> data[(*offset) ++] - 0x30;
if (current > 0xffffffffu) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
Expand Down Expand Up @@ -214,7 +215,7 @@ void load_PNM_frame (struct context * context, const struct PNM_image_header * h
switch (header -> type) {
case 1:
// sometimes the 0s and 1s are not delimited at all here, so it needs a special parser
while ((offset < (context -> size)) && ((context -> data[offset] & ~1u) != 0x30)) offset ++;
while ((offset < context -> size) && ((context -> data[offset] & ~1u) != 0x30)) offset ++;
if (offset >= context -> size) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
values[2] = values[1] = *values = ~context -> data[offset ++] & 1;
break;
Expand All @@ -228,10 +229,15 @@ void load_PNM_frame (struct context * context, const struct PNM_image_header * h
case 6: case 13: case 16:
if (header -> maxvalue > 0xff) {
*values = read_be16_unaligned(context -> data + offset);
values[1] = read_be16_unaligned(context -> data + (offset += 2));
values[2] = read_be16_unaligned(context -> data + (offset += 2));
if (header -> type >= 14) values[3] = read_be16_unaligned(context -> data + (offset += 2));
offset += 2;
values[1] = read_be16_unaligned(context -> data + offset);
offset += 2;
values[2] = read_be16_unaligned(context -> data + offset);
offset += 2;
if (header -> type >= 14) {
values[3] = read_be16_unaligned(context -> data + offset);
offset += 2;
}
} else {
*values = context -> data[offset ++];
values[1] = context -> data[offset ++];
Expand All @@ -242,8 +248,11 @@ void load_PNM_frame (struct context * context, const struct PNM_image_header * h
default:
if (header -> maxvalue > 0xff) {
*values = read_be16_unaligned(context -> data + offset);
if (header -> type >= 14) values[3] = read_be16_unaligned(context -> data + (offset += 2));
offset += 2;
if (header -> type >= 14) {
values[3] = read_be16_unaligned(context -> data + offset);
offset += 2;
}
} else {
*values = context -> data[offset ++];
if (header -> type >= 14) values[3] = context -> data[offset ++];
Expand Down
86 changes: 26 additions & 60 deletions src/pnmwrite.c
Original file line number Diff line number Diff line change
Expand Up @@ -181,75 +181,41 @@ size_t write_PNM_number (unsigned char * buffer, uint32_t number) {
}

void generate_PNM_frame_data (struct context * context, const uint64_t * data, uint32_t width, uint32_t height, unsigned bitdepth, int alpha) {
unsigned shift = 16 - bitdepth;
uint_fast8_t shift = 16 - bitdepth, mask = (1 << ((bitdepth > 8) ? bitdepth - 8 : bitdepth)) - 1;
size_t row, col;
if (shift >= 8) {
unsigned char * output = append_output_node(context, (size_t) (alpha ? 4 : 3) * width * height);
for (row = 0; row < height; row ++) {
const uint64_t * rowdata = data + row * context -> source -> width;
for (col = 0; col < width; col ++) {
uint64_t color = rowdata[col];
*(output ++) = (color & 0xffffu) >> shift;
*(output ++) = (color & 0xffff0000u) >> (shift + 16);
*(output ++) = (color & 0xffff00000000u) >> (shift + 32);
if (alpha) *(output ++) = color >> (shift + 48);
}
const uint64_t * rowdata = data;
unsigned char * output = append_output_node(context, (size_t) (3 + !!alpha) * ((bitdepth + 7) / 8) * width * height);
if (shift >= 8)
for (row = 0; row < height; row ++, rowdata += context -> source -> width) for (col = 0; col < width; col ++) {
output += byteappend(output, (rowdata[col] >> shift) & mask, (rowdata[col] >> (shift + 16)) & mask, (rowdata[col] >> (shift + 32)) & mask);
if (alpha) *(output ++) = rowdata[col] >> (shift + 48);
}
} else {
unsigned char * output = append_output_node(context, (size_t) (alpha ? 8 : 6) * width * height);
for (row = 0; row < height; row ++) {
const uint64_t * rowdata = data + row * context -> source -> width;
for (col = 0; col < width; col ++) {
uint64_t color = rowdata[col];
*(output ++) = (color & 0xffffu) >> (shift + 8);
*(output ++) = (color & 0xffffu) >> shift;
*(output ++) = (color & 0xffff0000u) >> (shift + 24);
*(output ++) = (color & 0xffff0000u) >> (shift + 16);
*(output ++) = (color & 0xffff00000000u) >> (shift + 40);
*(output ++) = (color & 0xffff00000000u) >> (shift + 32);
if (alpha) {
*(output ++) = color >> (shift + 56);
*(output ++) = color >> (shift + 48);
}
}
else
for (row = 0; row < height; row ++, rowdata += context -> source -> width) for (col = 0; col < width; col ++) {
output += byteappend(output, (rowdata[col] >> (shift + 8)) & mask, rowdata[col] >> shift, (rowdata[col] >> (shift + 24)) & mask,
rowdata[col] >> (shift + 16), (rowdata[col] >> (shift + 40)) & mask, rowdata[col] >> (shift + 32));
if (alpha) output += byteappend(output, rowdata[col] >> (shift + 56), rowdata[col] >> (shift + 48));
}
}
}

void generate_PNM_frame_data_from_palette (struct context * context, const uint8_t * data, const uint64_t * palette, uint32_t width, uint32_t height,
unsigned bitdepth, int alpha) {
// very similar to the previous function, but adjusted to use the color from the palette and to read 8-bit data
unsigned shift = 16 - bitdepth;
uint_fast8_t shift = 16 - bitdepth, mask = (1 << ((bitdepth > 8) ? bitdepth - 8 : bitdepth)) - 1;
size_t row, col;
if (shift >= 8) {
unsigned char * output = append_output_node(context, (size_t) (alpha ? 4 : 3) * width * height);
for (row = 0; row < height; row ++) {
const uint8_t * rowdata = data + row * context -> source -> width;
for (col = 0; col < width; col ++) {
uint64_t color = palette[rowdata[col]];
*(output ++) = (color & 0xffffu) >> shift;
*(output ++) = (color & 0xffff0000u) >> (shift + 16);
*(output ++) = (color & 0xffff00000000u) >> (shift + 32);
if (alpha) *(output ++) = color >> (shift + 48);
}
const uint8_t * rowdata = data;
unsigned char * output = append_output_node(context, (size_t) (3 + !!alpha) * ((bitdepth + 7) / 8) * width * height);
if (shift >= 8)
for (row = 0; row < height; row ++, rowdata += context -> source -> width) for (col = 0; col < width; col ++) {
uint64_t color = palette[rowdata[col]];
output += byteappend(output, (color >> shift) & mask, (color >> (shift + 16)) & mask, (color >> (shift + 32)) & mask);
if (alpha) *(output ++) = color >> (shift + 48);
}
} else {
unsigned char * output = append_output_node(context, (size_t) (alpha ? 8 : 6) * width * height);
for (row = 0; row < height; row ++) {
const uint8_t * rowdata = data + row * context -> source -> width;
for (col = 0; col < width; col ++) {
uint64_t color = palette[rowdata[col]];
*(output ++) = (color & 0xffffu) >> (shift + 8);
*(output ++) = (color & 0xffffu) >> shift;
*(output ++) = (color & 0xffff0000u) >> (shift + 24);
*(output ++) = (color & 0xffff0000u) >> (shift + 16);
*(output ++) = (color & 0xffff00000000u) >> (shift + 40);
*(output ++) = (color & 0xffff00000000u) >> (shift + 32);
if (alpha) {
*(output ++) = color >> (shift + 56);
*(output ++) = color >> (shift + 48);
}
}
else
for (row = 0; row < height; row ++, rowdata += context -> source -> width) for (col = 0; col < width; col ++) {
uint64_t color = palette[rowdata[col]];
output += byteappend(output, (color >> (shift + 8)) & mask, color >> shift, (color >> (shift + 24)) & mask, color >> (shift + 16),
(color >> (shift + 40)) & mask, color >> (shift + 32));
if (alpha) output += byteappend(output, color >> (shift + 56), color >> (shift + 48));
}
}
}
8 changes: 5 additions & 3 deletions src/store.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ size_t plum_store_image (const struct plum_image * image, void * restrict buffer
default: throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
}
size_t output_size = get_total_output_size(context);
if (!output_size) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
switch (size) {
case PLUM_FILENAME:
write_generated_image_data_to_file(context, buffer);
Expand Down Expand Up @@ -74,8 +75,9 @@ void write_generated_image_data_to_callback (struct context * context, const str
unsigned char * data = node -> data;
size_t size = node -> size;
while (size) {
int count = callback -> callback(callback -> userdata, data, (size > 0x4000) ? 0x4000 : size);
if (count < 0) throw(context, PLUM_ERR_FILE_ERROR);
int block = (size > 0x4000) ? 0x4000 : size;
int count = callback -> callback(callback -> userdata, data, block);
if ((count < 0) || (count > block)) throw(context, PLUM_ERR_FILE_ERROR);
data += count;
size -= count;
}
Expand All @@ -86,7 +88,7 @@ void write_generated_image_data_to_callback (struct context * context, const str
void write_generated_image_data (void * restrict buffer, const struct data_node * data) {
const struct data_node * node;
for (node = data; node -> previous; node = node -> previous);
char * out = buffer;
unsigned char * out = buffer;
while (node) {
memcpy(out, node -> data, node -> size);
out += node -> size;
Expand Down

0 comments on commit ec181e7

Please sign in to comment.