Skip to content

Commit

Permalink
Cleanup and better safety checks, 6
Browse files Browse the repository at this point in the history
  • Loading branch information
aaaaaa123456789 committed Jan 22, 2022
1 parent d90c627 commit a909b00
Show file tree
Hide file tree
Showing 7 changed files with 49 additions and 52 deletions.
25 changes: 13 additions & 12 deletions src/huffman.c
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#include "proto.h"

void generate_Huffman_tree (struct context * context, const size_t * restrict counts, unsigned char * restrict lengths, size_t entries, unsigned char max) {
size_t * sorted = ctxmalloc(context, 2 * entries * sizeof *sorted);
uint64_t * sorted = ctxmalloc(context, 2 * entries * sizeof *sorted);
size_t p, truecount = 0;
for (p = 0; p < entries; p ++) if (counts[p]) {
sorted[2 * truecount] = p;
sorted[2 * truecount + 1] = ~counts[p];
sorted[2 * truecount + 1] = ~(uint64_t) counts[p];
truecount ++;
}
memset(lengths, 0, entries);
Expand All @@ -17,7 +17,8 @@ void generate_Huffman_tree (struct context * context, const size_t * restrict co
size_t * parents = ctxmalloc(context, (entries + truecount) * sizeof *parents);
size_t * pendingnodes = ctxmalloc(context, truecount * sizeof *pendingnodes);
size_t * pendingcounts = ctxmalloc(context, truecount * sizeof *pendingcounts);
size_t sum, next = entries, remaining = truecount;
size_t sum, next = entries;
uint64_t remaining = truecount;
for (p = 0; p < truecount; p ++) {
pendingnodes[p] = sorted[2 * p];
pendingcounts[p] = counts[pendingnodes[p]];
Expand Down Expand Up @@ -59,32 +60,32 @@ void generate_Huffman_tree (struct context * context, const size_t * restrict co
ctxfree(context, parents);
if (sum <= max) goto done;
// the maximum length has been exceeded, so increase some other lengths to make everything fit
remaining = (size_t) 1 << max;
remaining = (uint64_t) 1 << max;
for (p = 0; p < truecount; p ++) {
next = sorted[p * 2];
if (lengths[next] > max) {
lengths[next] = max;
remaining --;
} else {
while (((size_t) 1 << (max - lengths[next])) > remaining) lengths[next] ++;
while ((remaining - ((size_t) 1 << (max - lengths[next]))) < (truecount - p - 1)) lengths[next] ++;
remaining -= (size_t) 1 << (max - lengths[next]);
while (((uint64_t) 1 << (max - lengths[next])) > remaining) lengths[next] ++;
while ((remaining - ((uint64_t) 1 << (max - lengths[next]))) < (truecount - p - 1)) lengths[next] ++;
remaining -= (uint64_t) 1 << (max - lengths[next]);
}
}
for (p = 0; remaining; p ++) {
next = sorted[p * 2];
while ((lengths[next] > 1) && (remaining >= ((size_t) 1 << (max - lengths[next])))) {
remaining -= (size_t) 1 << (max - lengths[next]);
while ((lengths[next] > 1) && (remaining >= ((uint64_t) 1 << (max - lengths[next])))) {
remaining -= (uint64_t) 1 << (max - lengths[next]);
lengths[next] --;
}
}
done:
ctxfree(context, sorted);
}

void generate_Huffman_codes (unsigned short * restrict codes, unsigned count, const unsigned char * restrict lengths, int invert) {
void generate_Huffman_codes (unsigned short * restrict codes, size_t count, const unsigned char * restrict lengths, int invert) {
// generates codes in ascending order: shorter codes before longer codes, and for the same length, smaller values before larger values
unsigned p, remaining = 0;
size_t p, remaining = 0;
for (p = 0; p < count; p ++) if (lengths[p]) remaining ++;
uint_fast8_t bits, length = 0;
uint_fast16_t temp, code = 0;
Expand All @@ -96,8 +97,8 @@ void generate_Huffman_codes (unsigned short * restrict codes, unsigned count, co
p = 0;
}
if (lengths[p] != length) continue;
// invert the code so it can be written out directly
if (invert) {
// for some image formats, invert the code so it can be written out directly (first branch at the LSB)
temp = code ++;
codes[p] = 0;
for (bits = 0; bits < length; bits ++) {
Expand Down
9 changes: 4 additions & 5 deletions src/jpegarithmetic.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ void decompress_JPEG_arithmetic_lossless_scan (struct context * context, struct
size_t rowunits, const struct JPEG_component_info * components, const size_t * offsets, unsigned char predictor,
unsigned precision) {
size_t p, restart_interval;
uint8_t scancomponents[4] = {0, 0, 0, 0};
uint8_t scancomponents[4] = {0};
for (p = 0; state -> MCU[p] != MCU_END_LIST; p ++) if (state -> MCU[p] < 4) scancomponents[state -> MCU[p]] = 1;
uint16_t * rowdifferences[4] = {0};
for (p = 0; p < 4; p ++) if (scancomponents[p])
Expand Down Expand Up @@ -322,10 +322,9 @@ unsigned next_JPEG_arithmetic_bit (struct context * context, size_t * restrict o
*accumulator = state -> probability;
}
if (index)
if (decoded) {
*index = predicted ? -state -> next_LPS : state -> next_LPS;
if (state -> switch_MPS) *index = -*index;
} else
if (decoded)
*index = (predicted ^ state -> switch_MPS) ? -state -> next_LPS : state -> next_LPS;
else
*index = predicted ? -state -> next_MPS : state -> next_MPS;
// normalize the counters, consuming new data if needed
do {
Expand Down
19 changes: 11 additions & 8 deletions src/jpeghierarchical.c
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ unsigned load_hierarchical_JPEG (struct context * context, const struct JPEG_mar
unsigned precision = context -> data[layout -> hierarchical + 2];
if ((precision < 2) || (precision > 16)) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
size_t p, frame, metadata_index = 0;
uint32_t component_size[8] = {0}; // four widths followed by four heights
uint16_t component_size[8] = {0}; // four widths followed by four heights
for (frame = 0; layout -> frames[frame]; frame ++) {
if (context -> data[layout -> frames[frame] + 2] != precision) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
uint32_t framecomponents = determine_JPEG_components(context, layout -> frames[frame]);
Expand Down Expand Up @@ -65,9 +65,9 @@ unsigned load_hierarchical_JPEG (struct context * context, const struct JPEG_mar
}
double normalization_offset;
if (precision < 15)
normalization_offset = 0x0.8p+0;
normalization_offset = 0.5;
else if (precision == 15)
normalization_offset = 0x0.4p+0;
normalization_offset = 0.25;
else
normalization_offset = 0.0;
for (p = 0; p < component_count; p ++) {
Expand Down Expand Up @@ -114,10 +114,13 @@ void expand_JPEG_component_vertically (struct context * context, double * restri
void normalize_JPEG_component (double * restrict component, size_t count, double offset) {
while (count --) {
double high = *component / 65536.0 + offset;
if (high >= 0)
high = -(int64_t) high;
else
high = 1 + (int64_t) -high;
*(component ++) += high * 65536.0;
// this merely calculates adjustment = -floor(high); not using floor() directly to avoid linking in the math library just for a single function
int64_t adjustment = 0;
if (high < 0) {
adjustment = 1 + (int64_t) -high;
high += adjustment;
}
adjustment -= (int64_t) high;
*(component ++) += adjustment * 65536.0;
}
}
35 changes: 16 additions & 19 deletions src/jpegread.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "proto.h"

void load_JPEG_data (struct context * context, unsigned flags, size_t limit) {
struct JPEG_marker_layout * layout = load_JPEG_marker_layout(context);
struct JPEG_marker_layout * layout = load_JPEG_marker_layout(context); // will be leaked (to be collected by context release)
uint32_t components = determine_JPEG_components(context, layout -> hierarchical ? layout -> hierarchical : *layout -> frames);
void (* transfer) (uint64_t * restrict, size_t, unsigned, const double **) = get_JPEG_component_transfer_function(context, layout, components);
context -> image -> type = PLUM_IMAGE_JPEG;
Expand Down Expand Up @@ -53,7 +53,6 @@ void load_JPEG_data (struct context * context, unsigned flags, size_t limit) {
if (error) throw(context, error);
}
}
// the marker layout is leaked, but it's small and it will be collected by the context release
}

struct JPEG_marker_layout * load_JPEG_marker_layout (struct context * context) {
Expand All @@ -62,7 +61,7 @@ struct JPEG_marker_layout * load_JPEG_marker_layout (struct context * context) {
uint_fast8_t next_restart_marker = 0; // 0 if not in a scan
size_t restart_offset, restart_interval, scan, frame = SIZE_MAX, markers = 0;
struct JPEG_marker_layout * layout = ctxmalloc(context, sizeof *layout);
*layout = (struct JPEG_marker_layout) {0}; // ensure that pointers are properly null-initialized
*layout = (struct JPEG_marker_layout) {0}; // ensure that integers and pointers are properly zero-initialized
while (offset < context -> size) {
prev = offset;
if (context -> data[offset ++] != 0xff)
Expand Down Expand Up @@ -101,19 +100,19 @@ struct JPEG_marker_layout * load_JPEG_marker_layout (struct context * context) {
layout -> framedata[frame][scan][restart_interval] = 0;
next_restart_marker = 0;
}
if ((offset + 2) > context -> size) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
if (offset > (context -> size - 2)) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
uint_fast16_t marker_size = read_be16_unaligned(context -> data + offset);
if ((marker_size < 2) || ((offset + marker_size) > context -> size)) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
if ((marker_size < 2) || (marker_size > context -> size) || (offset > (context -> size - marker_size))) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
switch (marker) {
case 0xc0: case 0xc1: case 0xc2: case 0xc3: case 0xc5: case 0xc6:
case 0xc7: case 0xc9: case 0xca: case 0xcb: case 0xcd: case 0xce: case 0xcf:
// start a new frame
if (frame != SIZE_MAX) {
if (scan == SIZE_MAX) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
layout -> framescans[frame] = ctxrealloc(context, layout -> framescans[frame], sizeof **layout -> framescans * ((++ scan) + 1));
layout -> framescans[frame][scan] = 0;
if (!scan) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
}
layout -> frames = ctxrealloc(context, layout -> frames, sizeof *layout -> frames * ((++ frame) + 1));
layout -> frames = ctxrealloc(context, layout -> frames, sizeof *layout -> frames * ((size_t) (++ frame) + 1));
layout -> frames[frame] = offset;
layout -> framescans = ctxrealloc(context, layout -> framescans, sizeof *layout -> framescans * (frame + 1));
layout -> framescans[frame] = NULL;
Expand All @@ -126,7 +125,7 @@ struct JPEG_marker_layout * load_JPEG_marker_layout (struct context * context) {
case 0xda:
// start a new scan
if (frame == SIZE_MAX) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
layout -> framescans[frame] = ctxrealloc(context, layout -> framescans[frame], sizeof **layout -> framescans * ((++ scan) + 1));
layout -> framescans[frame] = ctxrealloc(context, layout -> framescans[frame], sizeof **layout -> framescans * ((size_t) (++ scan) + 1));
layout -> framescans[frame][scan] = offset;
layout -> framedata[frame] = ctxrealloc(context, layout -> framedata[frame], sizeof **layout -> framedata * (scan + 1));
layout -> framedata[frame][scan] = NULL;
Expand All @@ -146,15 +145,15 @@ struct JPEG_marker_layout * load_JPEG_marker_layout (struct context * context) {
layout -> markertype = ctxrealloc(context, layout -> markertype, sizeof *layout -> markertype * (markers + 1));
layout -> markertype[markers ++] = marker;
break;
// For JFIF and Exif markers, both want to come "first", i.e., immediately after SOI. This is obviously impossible if both are present.
// For JFIF, Exif and Adobe markers, all want to come "first", i.e., immediately after SOI. This is obviously impossible if more than one is present.
// Therefore, "first" is interpreted to mean "before any SOF/DHP marker" here.
case 0xe0:
if (layout -> JFIF || layout -> hierarchical || (frame != SIZE_MAX)) break;
if ((marker_size >= 7) && bytematch(context -> data + offset + 2, 0x4a, 0x46, 0x49, 0x46, 0x00)) layout -> JFIF = offset;
break;
case 0xe1:
if (layout -> Exif || layout -> hierarchical || (frame != SIZE_MAX)) break;
if ((marker_size >= 7) && bytematch(context -> data + offset + 2, 0x45, 0x78, 0x69, 0x66, 0x00)) layout -> Exif = offset;
if ((marker_size >= 16) && bytematch(context -> data + offset + 2, 0x45, 0x78, 0x69, 0x66, 0x00, 0x00)) layout -> Exif = offset;
break;
case 0xee:
if (layout -> Adobe || layout -> hierarchical || (frame != SIZE_MAX)) break;
Expand Down Expand Up @@ -182,7 +181,6 @@ struct JPEG_marker_layout * load_JPEG_marker_layout (struct context * context) {
unsigned get_JPEG_rotation (struct context * context, size_t offset) {
// returns rotation count in bits 0-1 and vertical inversion in bit 2
uint_fast16_t size = read_be16_unaligned(context -> data + offset);
if ((size < 16) || !bytematch(context -> data + offset + 2, 0x45, 0x78, 0x69, 0x66, 0x00, 0x00)) return 0;
const unsigned char * data = context -> data + offset + 8;
size -= 8;
uint_fast16_t tag = read_le16_unaligned(data);
Expand All @@ -199,7 +197,7 @@ unsigned get_JPEG_rotation (struct context * context, size_t offset) {
if (pos > (size - 2)) return 0;
uint_fast16_t count = endianness ? read_be16_unaligned(data + pos) : read_le16_unaligned(data + pos);
pos += 2;
if ((size - pos) < ((uint32_t) count * 12)) return 0;
if ((size - pos) < ((uint_fast32_t) count * 12)) return 0;
for (; count; pos += 12, count --) {
tag = endianness ? read_be16_unaligned(data + pos) : read_le16_unaligned(data + pos);
if (tag == 0x112) break; // 0x112 = orientation data
Expand Down Expand Up @@ -258,14 +256,14 @@ unsigned char process_JPEG_metadata_until_offset (struct context * context, cons
case 0xcc: // DAC
if (markersize % 2) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
for (count = markersize / 2; count; count --) {
unsigned char destination = *(markerdata ++);
if (destination & ~0x13u) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
destination = (destination >> 2) | (destination & 3);
if (destination & 4) {
unsigned char target = *(markerdata ++);
if (target & ~0x13u) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
target = (target >> 2) | (target & 3);
if (target & 4) {
if (!*markerdata || (*markerdata > 63)) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
} else
if ((*markerdata >> 4) < (*markerdata & 15)) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
tables -> arithmetic[destination] = *(markerdata ++);
tables -> arithmetic[target] = *(markerdata ++);
}
break;
case 0xdb: // DQT
Expand All @@ -275,8 +273,7 @@ unsigned char process_JPEG_metadata_until_offset (struct context * context, cons
markerdata ++;
if ((-- markersize) < p) throw(context, PLUM_ERR_INVALID_FILE_FORMAT);
markersize -= p;
if (tables -> quantization[target]) ctxfree(context, tables -> quantization[target]);
tables -> quantization[target] = ctxmalloc(context, 64 * sizeof *(tables -> quantization[target]));
if (!tables -> quantization[target]) tables -> quantization[target] = ctxmalloc(context, 64 * sizeof *(tables -> quantization[target]));
if (type)
for (p = 0; p < 64; p ++, markerdata += 2) tables -> quantization[target][p] = read_be16_unaligned(markerdata);
else
Expand Down
7 changes: 2 additions & 5 deletions src/jpegwrite.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,12 @@ void generate_JPEG_data (struct context * context) {
ctxfree(context, luminance);
unsigned char Huffman_table_data[0x400]; // luminance DC, AC, chrominance DC, AC
node = append_output_node(context, 1096);
*node = 0xff;
node[1] = 0xc4; // DHT
size_t size = 4;
size += generate_JPEG_Huffman_table(context, luminance_data, luminance_count, node + size, Huffman_table_data, 0x00);
size += generate_JPEG_Huffman_table(context, luminance_data, luminance_count, node + size, Huffman_table_data + 0x100, 0x10);
size += generate_JPEG_Huffman_table(context, chrominance_data, chrominance_count, node + size, Huffman_table_data + 0x200, 0x01);
size += generate_JPEG_Huffman_table(context, chrominance_data, chrominance_count, node + size, Huffman_table_data + 0x300, 0x11);
node[2] = (size - 2) >> 8;
node[3] = size - 2;
bytewrite(node, 0xff, 0xc4, (size - 2) >> 8, size - 2); // DHT
context -> output -> size = size;
byteoutput(context, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, 0x00, 0x00, 0x3f, 0x00); // SOS, component 1, table 0, not progressive
encode_JPEG_scan(context, luminance_data, luminance_count, Huffman_table_data);
Expand Down Expand Up @@ -149,7 +146,7 @@ void convert_JPEG_components_to_YCbCr (struct context * context, double (* restr
#undef nextunit
}

void convert_JPEG_colors_to_YCbCr (struct context * context, const void * colors, size_t count, unsigned char flags, double * restrict luminance,
void convert_JPEG_colors_to_YCbCr (struct context * context, const void * restrict colors, size_t count, unsigned char flags, double * restrict luminance,
double * restrict blue, double * restrict red) {
uint64_t * buffer = ctxmalloc(context, sizeof *buffer * count);
plum_convert_colors(buffer, colors, count, PLUM_COLOR_64, flags);
Expand Down
2 changes: 1 addition & 1 deletion src/pngread.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ struct PNG_chunk_locations * load_PNG_chunk_locations (struct context * context)
size_t offset = 8;
uint32_t chunk_type = 0;
struct PNG_chunk_locations * result = ctxmalloc(context, sizeof *result);
*result = (struct PNG_chunk_locations) {0}; // ensure that pointers are properly null-initialized
*result = (struct PNG_chunk_locations) {0}; // ensure that integers and pointers are properly zero-initialized
size_t data_count = 0, frameinfo_count = 0, framedata_count = 0;
size_t * framedata = NULL;
int invalid_animation = 0;
Expand Down
4 changes: 2 additions & 2 deletions src/proto.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ internal void write_GIF_data_blocks(struct context *, const unsigned char * rest

// huffman.c
internal void generate_Huffman_tree(struct context *, const size_t * restrict, unsigned char * restrict, size_t, unsigned char);
internal void generate_Huffman_codes(unsigned short * restrict, unsigned, const unsigned char * restrict, int);
internal void generate_Huffman_codes(unsigned short * restrict, size_t, const unsigned char * restrict, int);

// jpegarithmetic.c
internal void decompress_JPEG_arithmetic_scan(struct context *, struct JPEG_decompressor_state * restrict, const struct JPEG_decoder_tables *, size_t,
Expand Down Expand Up @@ -208,7 +208,7 @@ internal void unpack_JPEG_component(double * restrict, double * restrict, size_t
internal void generate_JPEG_data(struct context *);
internal void calculate_JPEG_quantization_tables(struct context *, uint8_t [restrict static 64], uint8_t [restrict static 64]);
internal void convert_JPEG_components_to_YCbCr(struct context *, double (* restrict)[64], double (* restrict)[64], double (* restrict)[64]);
internal void convert_JPEG_colors_to_YCbCr(struct context *, const void *, size_t, unsigned char, double * restrict, double * restrict, double * restrict);
internal void convert_JPEG_colors_to_YCbCr(struct context *, const void * restrict, size_t, unsigned char, double * restrict, double * restrict, double * restrict);
internal void subsample_JPEG_component(double (* restrict)[64], double (* restrict)[64], size_t, size_t);

// load.c
Expand Down

0 comments on commit a909b00

Please sign in to comment.