aboutsummaryrefslogtreecommitdiffstats
path: root/libcoopgamma_get_gamma_recv.c
diff options
context:
space:
mode:
Diffstat (limited to 'libcoopgamma_get_gamma_recv.c')
-rw-r--r--libcoopgamma_get_gamma_recv.c148
1 files changed, 148 insertions, 0 deletions
diff --git a/libcoopgamma_get_gamma_recv.c b/libcoopgamma_get_gamma_recv.c
new file mode 100644
index 0000000..4207184
--- /dev/null
+++ b/libcoopgamma_get_gamma_recv.c
@@ -0,0 +1,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;
+}