aboutsummaryrefslogtreecommitdiffstats
path: root/libcoopgamma_get_gamma_recv.c
blob: 42071840ebf7d62e9e58274a87abf2d8fea7d27c (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/* See LICENSE file for copyright and license details. */
#include "common.h"


/**
 * Retrieve the current gamma ramp adjustments, receive response part
 * 
 * @param   table  Output for the response, must be initialised
 * @param   ctx    The state of the library, must be connected
 * @param   async  Information about the request
 * @return         Zero on success, -1 on error, in which case `ctx->error`
 *                 (rather than `errno`) is read for information about the error
 */
int
libcoopgamma_get_gamma_recv(libcoopgamma_filter_table_t *restrict table, libcoopgamma_context_t *restrict ctx,
                            libcoopgamma_async_context_t *restrict async)
{
	char temp[3 * sizeof(size_t) + 1];
	char *line;
	char *value;
	char *payload;
	size_t i, n, width, clutsize;
	int have_depth = 0;
	int have_red_size = 0;
	int have_green_size = 0;
	int have_blue_size = 0;
	int have_tables = 0;
	int bad = 0, r = 0, g = 0;
	size_t *out;
	size_t off, len;

	if (libcoopgamma_check_error__(ctx, async))
		return -1;

	libcoopgamma_filter_table_destroy(table);

	for (;;) {
		line = libcoopgamma_next_header__(ctx);
		value = &strchr(line, ':')[2U];
		if (!*line) {
			break;
		} else if (strstr(line, "Depth: ") == line) {
			have_depth = 1 + !!have_depth;
			if      (!strcmp(value, "8"))  table->depth = LIBCOOPGAMMA_UINT8;
			else if (!strcmp(value, "16")) table->depth = LIBCOOPGAMMA_UINT16;
			else if (!strcmp(value, "32")) table->depth = LIBCOOPGAMMA_UINT32;
			else if (!strcmp(value, "64")) table->depth = LIBCOOPGAMMA_UINT64;
			else if (!strcmp(value, "f"))  table->depth = LIBCOOPGAMMA_FLOAT;
			else if (!strcmp(value, "d"))  table->depth = LIBCOOPGAMMA_DOUBLE;
			else
				bad = 1;
		} else if ((r = (strstr(line, "Red size: ")   == line)) ||
		           (g = (strstr(line, "Green size: ") == line)) ||
		                 strstr(line, "Blue size: ")  == line) {
			if (r)      have_red_size   = 1 + !!have_red_size,   out = &table->red_size;
			else if (g) have_green_size = 1 + !!have_green_size, out = &table->green_size;
			else        have_blue_size  = 1 + !!have_blue_size,  out = &table->blue_size;
			*out = (size_t)atol(value);
			sprintf(temp, "%zu", *out);
			if (strcmp(value, temp))
				bad = 1;
		} else if (strstr(line, "Tables: ") == line) {
			have_tables = 1 + have_tables;
			table->filter_count = (size_t)atol(value);
			sprintf(temp, "%zu", table->filter_count);
			if (strcmp(value, temp))
				bad = 1;
		}
	}

	payload = libcoopgamma_next_payload__(ctx, &n);

	if (bad || have_depth != 1 || have_red_size != 1 || have_green_size != 1 ||
	    have_blue_size != 1 || (async->coalesce ? have_tables > 1 : !have_tables) ||
	    ((!payload || !n) && (async->coalesce || table->filter_count > 0)) ||
	    (n > 0 && have_tables && !table->filter_count) ||
	    (async->coalesce && have_tables && table->filter_count != 1))
		goto bad;

	switch (table->depth) {
	case LIBCOOPGAMMA_FLOAT:  width = sizeof(float);  break;
	case LIBCOOPGAMMA_DOUBLE: width = sizeof(double); break;
	default: INTEGRAL_DEPTHS
		if (table->depth <= 0 || (table->depth & 7))
			goto bad;
		width = (size_t)(table->depth / 8);
		break;
	}

	clutsize = table->red_size + table->green_size + table->blue_size;
	clutsize *= width;

	if (async->coalesce) {
		if (n != clutsize)
			goto bad;
		table->filters = malloc(sizeof(*(table->filters)));
		if (!table->filters)
			goto fail;
		table->filters->priority = 0;
		table->filters->class = NULL;
		table->filters->ramps.u8.red_size   = table->red_size;
		table->filters->ramps.u8.green_size = table->green_size;
		table->filters->ramps.u8.blue_size  = table->blue_size;
		if (libcoopgamma_ramps_initialise_(&table->filters->ramps, width) < 0)
			goto fail;
		memcpy(table->filters->ramps.u8.red, payload, clutsize);
		table->filter_count = 1;
	} else if (!table->filter_count) {
		table->filters = NULL;
	} else {
		off = 0;
		table->filters = calloc(table->filter_count, sizeof(*table->filters));
		if (!table->filters)
			goto fail;
		for (i = 0; i < table->filter_count; i++) {
			if (off + sizeof(int64_t) > n)
				goto bad;
			table->filters[i].priority = *(int64_t *)&payload[off];
			off += sizeof(int64_t);
			if (!memchr(&payload[off], '\0', n - off))
				goto bad;
			len = strlen(&payload[off]) + 1U;
			table->filters[i].class = malloc(len);
			if (!table->filters[i].class)
				goto fail;
			memcpy(table->filters[i].class, &payload[off], len);
			off += len;
			if (off + clutsize > n)
				goto bad;
			table->filters[i].ramps.u8.red_size   = table->red_size;
			table->filters[i].ramps.u8.green_size = table->green_size;
			table->filters[i].ramps.u8.blue_size  = table->blue_size;
			if (libcoopgamma_ramps_initialise_(&table->filters[i].ramps, width) < 0)
				goto fail;
			memcpy(table->filters[i].ramps.u8.red, &payload[off], clutsize);
			off += clutsize;
		}
		if (off != n)
			goto bad;
	}

	return 0;
bad:
	errno = EBADMSG;
fail:
	copy_errno(ctx);
	return -1;
}