#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <gimp-print/gimp-print.h>
#include <gimp-print/sequence.h>
#include "gimp-print-internal.h"
#include <gimp-print/gimp-print-intl-internal.h>
#include <math.h>
#ifdef sun
#include <ieeefp.h>
#endif
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <errno.h>
#include <ctype.h>
struct stp_sequence
{
int recompute_range;
double blo;
double bhi;
double rlo;
double rhi;
size_t size;
double *data;
float *float_data;
long *long_data;
unsigned long *ulong_data;
int *int_data;
unsigned *uint_data;
short *short_data;
unsigned short *ushort_data;
};
static inline void
check_sequence(const stp_sequence_t *v)
{
if (v == NULL)
{
stp_erprintf("Null stp_sequence_t! Please report this bug.\n");
stp_abort();
}
}
static void
sequence_ctor(stp_sequence_t *sequence)
{
sequence->rlo = sequence->blo = 0.0;
sequence->rhi = sequence->bhi = 1.0;
sequence->recompute_range = 1;
sequence->size = 0;
sequence->data = NULL;
}
stp_sequence_t *
stp_sequence_create(void)
{
stp_sequence_t *ret;
ret = stp_zalloc(sizeof(stp_sequence_t));
sequence_ctor(ret);
return ret;
}
static void
invalidate_auxilliary_data(stp_sequence_t *sequence)
{
STP_SAFE_FREE(sequence->float_data);
STP_SAFE_FREE(sequence->long_data);
STP_SAFE_FREE(sequence->ulong_data);
STP_SAFE_FREE(sequence->int_data);
STP_SAFE_FREE(sequence->uint_data);
STP_SAFE_FREE(sequence->short_data);
STP_SAFE_FREE(sequence->ushort_data);
}
static void
sequence_dtor(stp_sequence_t *sequence)
{
invalidate_auxilliary_data(sequence);
if (sequence->data)
stp_free(sequence->data);
memset(sequence, 0, sizeof(stp_sequence_t));
}
void
stp_sequence_destroy(stp_sequence_t *sequence)
{
check_sequence(sequence);
sequence_dtor(sequence);
stp_free(sequence);
}
void
stp_sequence_copy(stp_sequence_t *dest, const stp_sequence_t *source)
{
check_sequence(dest);
check_sequence(source);
dest->recompute_range = source->recompute_range;
dest->blo = source->blo;
dest->bhi = source->bhi;
dest->rlo = source->rlo;
dest->rhi = source->rhi;
dest->size = source->size;
dest->data = stp_zalloc(sizeof(double) * source->size);
memcpy(dest->data, source->data, (sizeof(double) * source->size));
}
stp_sequence_t *
stp_sequence_create_copy(const stp_sequence_t *sequence)
{
stp_sequence_t *ret;
check_sequence(sequence);
ret = stp_sequence_create();
stp_sequence_copy(ret, sequence);
return ret;
}
int
stp_sequence_set_bounds(stp_sequence_t *sequence, double low, double high)
{
check_sequence(sequence);
if (low > high)
return 0;
sequence->rlo = sequence->blo = low;
sequence->rhi = sequence->bhi = high;
sequence->recompute_range = 1;
return 1;
}
void
stp_sequence_get_bounds(const stp_sequence_t *sequence,
double *low, double *high)
{
check_sequence(sequence);
*low = sequence->blo;
*high = sequence->bhi;
}
static void
scan_sequence_range(stp_sequence_t *sequence)
{
int i;
sequence->rlo = sequence->bhi;
sequence->rhi = sequence->blo;
if (sequence->size)
for (i = 0; i < sequence->size; i++)
{
if (sequence->data[i] < sequence->rlo)
sequence->rlo = sequence->data[i];
if (sequence->data[i] > sequence->rhi)
sequence->rhi = sequence->data[i];
}
sequence->recompute_range = 0;
}
void
stp_sequence_get_range(const stp_sequence_t *sequence,
double *low, double *high)
{
if (sequence->recompute_range)
scan_sequence_range((stp_sequence_t *) sequence);
*low = sequence->rlo;
*high = sequence->rhi;
}
int
stp_sequence_set_size(stp_sequence_t *sequence, size_t size)
{
check_sequence(sequence);
if (sequence->data)
{
stp_free(sequence->data);
sequence->data = NULL;
}
sequence->size = size;
sequence->recompute_range = 1;
if (size == 0)
return 1;
invalidate_auxilliary_data(sequence);
sequence->data = stp_zalloc(sizeof(double) * size);
return 1;
}
size_t
stp_sequence_get_size(const stp_sequence_t *sequence)
{
check_sequence(sequence);
return sequence->size;
}
int
stp_sequence_set_data(stp_sequence_t *sequence,
size_t size, const double *data)
{
check_sequence(sequence);
sequence->size = size;
if (sequence->data)
stp_free(sequence->data);
sequence->data = stp_zalloc(sizeof(double) * size);
memcpy(sequence->data, data, (sizeof(double) * size));
invalidate_auxilliary_data(sequence);
sequence->recompute_range = 1;
return 1;
}
int
stp_sequence_set_subrange(stp_sequence_t *sequence, size_t where,
size_t size, const double *data)
{
check_sequence(sequence);
if (where + size > sequence->size)
return 0;
memcpy(sequence->data+where, data, (sizeof(double) * size));
invalidate_auxilliary_data(sequence);
sequence->recompute_range = 1;
return 1;
}
void
stp_sequence_get_data(const stp_sequence_t *sequence, size_t *size,
const double **data)
{
check_sequence(sequence);
*size = sequence->size;
*data = sequence->data;
}
int
stp_sequence_set_point(stp_sequence_t *sequence, size_t where,
double data)
{
check_sequence(sequence);
if (where >= sequence->size || ! finite(data) ||
data < sequence->blo || data > sequence->bhi)
return 0;
if (sequence->recompute_range == 0 && (data < sequence->rlo ||
data > sequence->rhi ||
sequence->data[where] == sequence->rhi ||
sequence->data[where] == sequence->rlo))
sequence->recompute_range = 1;
sequence->data[where] = data;
invalidate_auxilliary_data(sequence);
return 1;
}
int
stp_sequence_get_point(const stp_sequence_t *sequence, size_t where,
double *data)
{
check_sequence(sequence);
if (where >= sequence->size)
return 0;
*data = sequence->data[where];
return 1;
}
stp_sequence_t *
stp_sequence_create_from_xmltree(stp_mxml_node_t *da)
{
const char *stmp;
stp_sequence_t *ret = NULL;
size_t point_count;
double low, high;
int i;
ret = stp_sequence_create();
stmp = stp_mxmlElementGetAttr(da, "count");
if (stmp)
{
point_count = (size_t) stp_xmlstrtoul(stmp);
if ((stp_xmlstrtol(stmp)) < 0)
{
stp_erprintf("stp_sequence_create_from_xmltree: \"count\" is less than zero\n");
goto error;
}
}
else
{
stp_erprintf("stp_sequence_create_from_xmltree: \"count\" missing\n");
goto error;
}
stmp = stp_mxmlElementGetAttr(da, "lower-bound");
if (stmp)
{
low = stp_xmlstrtod(stmp);
}
else
{
stp_erprintf("stp_sequence_create_from_xmltree: \"lower-bound\" missing\n");
goto error;
}
stmp = stp_mxmlElementGetAttr(da, "upper-bound");
if (stmp)
{
high = stp_xmlstrtod(stmp);
}
else
{
stp_erprintf("stp_sequence_create_from_xmltree: \"upper-bound\" missing\n");
goto error;
}
stp_deprintf(STP_DBG_XML,
"stp_sequence_create_from_xmltree: stp_sequence_set_size: %d\n",
point_count);
stp_sequence_set_size(ret, point_count);
stp_sequence_set_bounds(ret, low, high);
if (point_count)
{
stp_mxml_node_t *child = da->child;
i = 0;
while (child && i < point_count)
{
if (child->type == STP_MXML_TEXT)
{
char *endptr;
double tmpval = strtod(child->value.text.string, &endptr);
if (endptr == child->value.text.string)
{
stp_erprintf
("stp_sequence_create_from_xmltree: bad data %s\n",
child->value.text.string);
goto error;
}
if (! finite(tmpval)
|| ( tmpval == 0 && errno == ERANGE )
|| tmpval < low
|| tmpval > high)
{
stp_erprintf("stp_sequence_create_from_xmltree: "
"read aborted: datum out of bounds: "
"%g (require %g <= x <= %g), n = %d\n",
tmpval, low, high, i);
goto error;
}
stp_sequence_set_point(ret, i, tmpval);
i++;
child = child->next;
}
}
if (i < point_count)
{
stp_erprintf("stp_sequence_create_from_xmltree: "
"read aborted: too little data "
"(n=%d, needed %d)\n", i, point_count);
goto error;
}
}
return ret;
error:
stp_erprintf("stp_sequence_create_from_xmltree: error during sequence read\n");
if (ret)
stp_sequence_destroy(ret);
return NULL;
}
stp_mxml_node_t *
stp_xmltree_create_from_sequence(const stp_sequence_t *seq)
{
size_t pointcount;
double low;
double high;
char *count;
char *lower_bound;
char *upper_bound;
stp_mxml_node_t *seqnode;
int i;
pointcount = stp_sequence_get_size(seq);
stp_sequence_get_bounds(seq, &low, &high);
stp_asprintf(&count, "%lu", (unsigned long) pointcount);
stp_asprintf(&lower_bound, "%g", low);
stp_asprintf(&upper_bound, "%g", high);
seqnode = stp_mxmlNewElement(NULL, "sequence");
(void) stp_mxmlElementSetAttr(seqnode, "count", count);
(void) stp_mxmlElementSetAttr(seqnode, "lower-bound", lower_bound);
(void) stp_mxmlElementSetAttr(seqnode, "upper-bound", upper_bound);
stp_free(count);
stp_free(lower_bound);
stp_free(upper_bound);
if (pointcount)
{
for (i = 0; i < pointcount; i++)
{
double dval;
char *sval;
if ((stp_sequence_get_point(seq, i, &dval)) != 1)
goto error;
stp_asprintf(&sval, "%g", dval);
stp_mxmlNewText(seqnode, 1, sval);
stp_free(sval);
}
}
return seqnode;
error:
if (seqnode)
stp_mxmlDelete(seqnode);
return NULL;
}
#define DEFINE_DATA_SETTER(t, name) \
int \
stp_sequence_set_##name##_data(stp_sequence_t *sequence, \
size_t count, const t *data) \
{ \
int i; \
check_sequence(sequence); \
if (count < 2) \
return 0; \
\
\
for (i = 0; i < count; i++) \
if (! finite(data[i]) || \
data[i] < sequence->blo || \
data[i] > sequence->bhi) \
return 0; \
stp_sequence_set_size(sequence, count); \
for (i = 0; i < count; i++) \
stp_sequence_set_point(sequence, i, (double) data[i]); \
return 1; \
}
DEFINE_DATA_SETTER(float, float)
DEFINE_DATA_SETTER(long, long)
DEFINE_DATA_SETTER(unsigned long, ulong)
DEFINE_DATA_SETTER(int, int)
DEFINE_DATA_SETTER(unsigned int, uint)
DEFINE_DATA_SETTER(short, short)
DEFINE_DATA_SETTER(unsigned short, ushort)
#define DEFINE_DATA_ACCESSOR(t, lb, ub, name) \
const t * \
stp_sequence_get_##name##_data(const stp_sequence_t *sequence, size_t *count) \
{ \
int i; \
if (sequence->blo < (double) lb || sequence->bhi > (double) ub) \
return NULL; \
if (!sequence->name##_data) \
{ \
((stp_sequence_t *)sequence)->name##_data = stp_zalloc(sizeof(t) * sequence->size); \
for (i = 0; i < sequence->size; i++) \
((stp_sequence_t *)sequence)->name##_data[i] = (t) sequence->data[i]; \
} \
*count = sequence->size; \
return sequence->name##_data; \
}
#ifndef HUGE_VALF
#define HUGE_VALF 3.402823466E+38F
#endif
DEFINE_DATA_ACCESSOR(float, -HUGE_VALF, HUGE_VALF, float)
DEFINE_DATA_ACCESSOR(long, LONG_MIN, LONG_MAX, long)
DEFINE_DATA_ACCESSOR(unsigned long, 0, ULONG_MAX, ulong)
DEFINE_DATA_ACCESSOR(int, INT_MIN, INT_MAX, int)
DEFINE_DATA_ACCESSOR(unsigned int, 0, UINT_MAX, uint)
DEFINE_DATA_ACCESSOR(short, SHRT_MIN, SHRT_MAX, short)
DEFINE_DATA_ACCESSOR(unsigned short, 0, USHRT_MAX, ushort)