diff --git a/src/pngwrite.c b/src/pngwrite.c index 2b488ab..33a43ab 100644 --- a/src/pngwrite.c +++ b/src/pngwrite.c @@ -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); } diff --git a/src/pnmread.c b/src/pnmread.c index 28e6b10..a1687f4 100644 --- a/src/pnmread.c +++ b/src/pnmread.c @@ -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); @@ -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; } @@ -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); @@ -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; @@ -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 ++]; @@ -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 ++]; diff --git a/src/pnmwrite.c b/src/pnmwrite.c index 7bab311..09b9944 100644 --- a/src/pnmwrite.c +++ b/src/pnmwrite.c @@ -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)); } - } } diff --git a/src/store.c b/src/store.c index 45645e6..99fa685 100644 --- a/src/store.c +++ b/src/store.c @@ -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); @@ -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; } @@ -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;