1/*
2 * "$Id: sequence.c,v 1.29 2011/02/17 02:15:18 rlk Exp $"
3 *
4 *   Sequence data type.  This type is designed to be derived from by
5 *   the curve and dither matrix types.
6 *
7 *   Copyright 2002-2003 Robert Krawitz (rlk@alum.mit.edu)
8 *   Copyright 2003      Roger Leigh (rleigh@debian.org)
9 *
10 *   This program is free software; you can redistribute it and/or modify it
11 *   under the terms of the GNU General Public License as published by the Free
12 *   Software Foundation; either version 2 of the License, or (at your option)
13 *   any later version.
14 *
15 *   This program is distributed in the hope that it will be useful, but
16 *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
18 *   for more details.
19 *
20 *   You should have received a copy of the GNU General Public License
21 *   along with this program; if not, write to the Free Software
22 *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 */
24
25#ifdef HAVE_CONFIG_H
26#include <config.h>
27#endif
28#include <gutenprint/gutenprint.h>
29#include <gutenprint/sequence.h>
30#include "gutenprint-internal.h"
31#include <gutenprint/gutenprint-intl-internal.h>
32#include <math.h>
33#ifdef sun
34#include <ieeefp.h>
35#endif
36#include <string.h>
37#include <stdlib.h>
38#include <limits.h>
39#include <errno.h>
40#include <ctype.h>
41
42struct stp_sequence
43{
44  int recompute_range; /* Do we need to recompute the min and max? */
45  double blo;          /* Lower bound */
46  double bhi;          /* Upper bound */
47  double rlo;          /* Lower range limit */
48  double rhi;          /* Upper range limit */
49  size_t size;         /* Number of points */
50  double *data;        /* Array of doubles */
51  float *float_data;   /* Data converted to other form */
52  long *long_data;
53  unsigned long *ulong_data;
54  int *int_data;
55  unsigned *uint_data;
56  short *short_data;
57  unsigned short *ushort_data;
58};
59
60/*
61 * We could do more sanity checks here if we want.
62 */
63
64#define CHECK_SEQUENCE(sequence) STPI_ASSERT(sequence, NULL)
65
66static inline stp_sequence_t *
67deconst_sequence(const stp_sequence_t *sequence)
68{
69  return (stp_sequence_t *) sequence;
70}
71
72static void
73sequence_ctor(stp_sequence_t *sequence)
74{
75  sequence->rlo = sequence->blo = 0.0;
76  sequence->rhi = sequence->bhi = 1.0;
77  sequence->recompute_range = 1;
78  sequence->size = 0;
79  sequence->data = NULL;
80}
81
82stp_sequence_t *
83stp_sequence_create(void)
84{
85  stp_sequence_t *ret;
86  ret = stp_zalloc(sizeof(stp_sequence_t));
87  sequence_ctor(ret);
88  return ret;
89}
90
91static void
92invalidate_auxilliary_data(stp_sequence_t *sequence)
93{
94  STP_SAFE_FREE(sequence->float_data);
95  STP_SAFE_FREE(sequence->long_data);
96  STP_SAFE_FREE(sequence->ulong_data);
97  STP_SAFE_FREE(sequence->int_data);
98  STP_SAFE_FREE(sequence->uint_data);
99  STP_SAFE_FREE(sequence->short_data);
100  STP_SAFE_FREE(sequence->ushort_data);
101}
102
103static void
104sequence_dtor(stp_sequence_t *sequence)
105{
106  invalidate_auxilliary_data(sequence);
107  if (sequence->data)
108    stp_free(sequence->data);
109  memset(sequence, 0, sizeof(stp_sequence_t));
110}
111
112void
113stp_sequence_destroy(stp_sequence_t *sequence)
114{
115  CHECK_SEQUENCE(sequence);
116  sequence_dtor(sequence);
117  stp_free(sequence);
118}
119
120void
121stp_sequence_copy(stp_sequence_t *dest, const stp_sequence_t *source)
122{
123  CHECK_SEQUENCE(dest);
124  CHECK_SEQUENCE(source);
125
126  dest->recompute_range = source->recompute_range;
127  dest->blo = source->blo;
128  dest->bhi = source->bhi;
129  dest->rlo = source->rlo;
130  dest->rhi = source->rhi;
131  dest->size = source->size;
132  dest->data = stp_zalloc(sizeof(double) * source->size);
133  memcpy(dest->data, source->data, (sizeof(double) * source->size));
134}
135
136void
137stp_sequence_reverse(stp_sequence_t *dest, const stp_sequence_t *source)
138{
139  int i;
140  CHECK_SEQUENCE(dest);
141  CHECK_SEQUENCE(source);
142
143  dest->recompute_range = source->recompute_range;
144  dest->blo = source->blo;
145  dest->bhi = source->bhi;
146  dest->rlo = source->rlo;
147  dest->rhi = source->rhi;
148  dest->size = source->size;
149  dest->data = stp_zalloc(sizeof(double) * source->size);
150  for (i = 0; i < source->size; i++)
151    dest->data[i] = source->data[source->size - i - 1];
152}
153
154stp_sequence_t *
155stp_sequence_create_copy(const stp_sequence_t *sequence)
156{
157  stp_sequence_t *ret;
158  CHECK_SEQUENCE(sequence);
159  ret = stp_sequence_create();
160  stp_sequence_copy(ret, sequence);
161  return ret;
162}
163
164stp_sequence_t *
165stp_sequence_create_reverse(const stp_sequence_t *sequence)
166{
167  stp_sequence_t *ret;
168  CHECK_SEQUENCE(sequence);
169  ret = stp_sequence_create();
170  stp_sequence_reverse(ret, sequence);
171  return ret;
172}
173
174int
175stp_sequence_set_bounds(stp_sequence_t *sequence, double low, double high)
176{
177  CHECK_SEQUENCE(sequence);
178  if (low > high)
179    return 0;
180  sequence->rlo = sequence->blo = low;
181  sequence->rhi = sequence->bhi = high;
182  sequence->recompute_range = 1;
183  return 1;
184}
185
186void
187stp_sequence_get_bounds(const stp_sequence_t *sequence,
188			double *low, double *high)
189{
190  CHECK_SEQUENCE(sequence);
191  *low = sequence->blo;
192  *high = sequence->bhi;
193}
194
195
196/*
197 * Find the minimum and maximum points on the curve.
198 */
199static void
200scan_sequence_range(stp_sequence_t *sequence)
201{
202  int i;
203  sequence->rlo = sequence->bhi;
204  sequence->rhi = sequence->blo;
205  if (sequence->size)
206    for (i = 0; i < sequence->size; i++)
207      {
208	if (sequence->data[i] < sequence->rlo)
209	  sequence->rlo = sequence->data[i];
210	if (sequence->data[i] > sequence->rhi)
211	  sequence->rhi = sequence->data[i];
212      }
213  sequence->recompute_range = 0; /* Don't recompute unless the data changes */
214}
215
216void
217stp_sequence_get_range(const stp_sequence_t *sequence,
218		       double *low, double *high)
219{
220  if (sequence->recompute_range) /* Don't recompute the range if we don't
221			       need to. */
222    scan_sequence_range(deconst_sequence(sequence));
223  *low = sequence->rlo;
224  *high = sequence->rhi;
225}
226
227
228int
229stp_sequence_set_size(stp_sequence_t *sequence, size_t size)
230{
231  CHECK_SEQUENCE(sequence);
232  if (sequence->data) /* Free old data */
233    {
234      stp_free(sequence->data);
235      sequence->data = NULL;
236    }
237  sequence->size = size;
238  sequence->recompute_range = 1; /* Always recompute on change */
239  if (size == 0)
240    return 1;
241  invalidate_auxilliary_data(sequence);
242  sequence->data = stp_zalloc(sizeof(double) * size);
243  return 1;
244}
245
246
247size_t
248stp_sequence_get_size(const stp_sequence_t *sequence)
249{
250  CHECK_SEQUENCE(sequence);
251  return sequence->size;
252}
253
254
255
256int
257stp_sequence_set_data(stp_sequence_t *sequence,
258		      size_t size, const double *data)
259{
260  CHECK_SEQUENCE(sequence);
261  sequence->size = size;
262  if (sequence->data)
263    stp_free(sequence->data);
264  sequence->data = stp_zalloc(sizeof(double) * size);
265  memcpy(sequence->data, data, (sizeof(double) * size));
266  invalidate_auxilliary_data(sequence);
267  sequence->recompute_range = 1;
268  return 1;
269}
270
271int
272stp_sequence_set_subrange(stp_sequence_t *sequence, size_t where,
273			  size_t size, const double *data)
274{
275  CHECK_SEQUENCE(sequence);
276  if (where + size > sequence->size) /* Exceeds data size */
277    return 0;
278  memcpy(sequence->data+where, data, (sizeof(double) * size));
279  invalidate_auxilliary_data(sequence);
280  sequence->recompute_range = 1;
281  return 1;
282}
283
284
285void
286stp_sequence_get_data(const stp_sequence_t *sequence, size_t *size,
287		      const double **data)
288{
289  CHECK_SEQUENCE(sequence);
290  *size = sequence->size;
291  *data = sequence->data;
292}
293
294
295int
296stp_sequence_set_point(stp_sequence_t *sequence, size_t where,
297		       double data)
298{
299  CHECK_SEQUENCE(sequence);
300
301  if (where >= sequence->size || ! isfinite(data) ||
302      data < sequence->blo || data > sequence->bhi)
303    return 0;
304
305  if (sequence->recompute_range == 0 && (data < sequence->rlo ||
306					 data > sequence->rhi ||
307					 sequence->data[where] == sequence->rhi ||
308					 sequence->data[where] == sequence->rlo))
309    sequence->recompute_range = 1;
310
311  sequence->data[where] = data;
312  invalidate_auxilliary_data(sequence);
313  return 1;
314}
315
316int
317stp_sequence_get_point(const stp_sequence_t *sequence, size_t where,
318		       double *data)
319{
320  CHECK_SEQUENCE(sequence);
321
322  if (where >= sequence->size)
323    return 0;
324  *data = sequence->data[where];
325  return 1;
326}
327
328stp_sequence_t *
329stp_sequence_create_from_xmltree(stp_mxml_node_t *da)
330{
331  const char *stmp;
332  stp_sequence_t *ret = NULL;
333  size_t point_count;
334  double low, high;
335  int i;
336
337  ret = stp_sequence_create();
338
339  /* Get curve point count */
340  stmp = stp_mxmlElementGetAttr(da, "count");
341  if (stmp)
342    {
343      point_count = (size_t) stp_xmlstrtoul(stmp);
344      if ((stp_xmlstrtol(stmp)) < 0)
345	{
346	  stp_erprintf("stp_sequence_create_from_xmltree: \"count\" is less than zero\n");
347	  goto error;
348	}
349    }
350  else
351    {
352      stp_erprintf("stp_sequence_create_from_xmltree: \"count\" missing\n");
353      goto error;
354    }
355  /* Get lower bound */
356  stmp = stp_mxmlElementGetAttr(da, "lower-bound");
357  if (stmp)
358    {
359      low = stp_xmlstrtod(stmp);
360    }
361  else
362    {
363      stp_erprintf("stp_sequence_create_from_xmltree: \"lower-bound\" missing\n");
364      goto error;
365    }
366  /* Get upper bound */
367  stmp = stp_mxmlElementGetAttr(da, "upper-bound");
368  if (stmp)
369    {
370      high = stp_xmlstrtod(stmp);
371    }
372  else
373    {
374      stp_erprintf("stp_sequence_create_from_xmltree: \"upper-bound\" missing\n");
375      goto error;
376    }
377
378  stp_deprintf(STP_DBG_XML,
379	       "stp_sequence_create_from_xmltree: stp_sequence_set_size: %ld\n",
380	       (long)point_count);
381  stp_sequence_set_size(ret, point_count);
382  stp_sequence_set_bounds(ret, low, high);
383
384  /* Now read in the data points */
385  if (point_count)
386    {
387      stp_mxml_node_t *child = da->child;
388      i = 0;
389      while (child && i < point_count)
390	{
391	  if (child->type == STP_MXML_TEXT)
392	    {
393	      char *endptr;
394	      double tmpval = strtod(child->value.text.string, &endptr);
395	      if (endptr == child->value.text.string)
396		{
397		  stp_erprintf
398		    ("stp_sequence_create_from_xmltree: bad data %s\n",
399		     child->value.text.string);
400		  goto error;
401		}
402	      if (! isfinite(tmpval)
403		  || ( tmpval == 0 && errno == ERANGE )
404		  || tmpval < low
405		  || tmpval > high)
406		{
407		  stp_erprintf("stp_sequence_create_from_xmltree: "
408			       "read aborted: datum out of bounds: "
409			       "%g (require %g <= x <= %g), n = %d\n",
410			       tmpval, low, high, i);
411		  goto error;
412		}
413	      /* Datum was valid, so now add to the sequence */
414	      stp_sequence_set_point(ret, i, tmpval);
415	      i++;
416	    }
417	  child = child->next;
418	}
419      if (i < point_count)
420	{
421	  stp_erprintf("stp_sequence_create_from_xmltree: "
422		       "read aborted: too little data "
423		       "(n=%d, needed %ld)\n", i, (long)point_count);
424	  goto error;
425	}
426    }
427
428  return ret;
429
430 error:
431  stp_erprintf("stp_sequence_create_from_xmltree: error during sequence read\n");
432  if (ret)
433    stp_sequence_destroy(ret);
434  return NULL;
435}
436
437stp_mxml_node_t *
438stp_xmltree_create_from_sequence(const stp_sequence_t *seq)   /* The sequence */
439{
440  size_t pointcount;
441  double low;
442  double high;
443
444  char *count;
445  char *lower_bound;
446  char *upper_bound;
447
448  stp_mxml_node_t *seqnode;
449
450  int i;                 /* loop counter */
451
452  pointcount = stp_sequence_get_size(seq);
453  stp_sequence_get_bounds(seq, &low, &high);
454
455  /* should count be of greater precision? */
456  stp_asprintf(&count, "%lu", (unsigned long) pointcount);
457  stp_asprintf(&lower_bound, "%g", low);
458  stp_asprintf(&upper_bound, "%g", high);
459
460  seqnode = stp_mxmlNewElement(NULL, "sequence");
461  (void) stp_mxmlElementSetAttr(seqnode, "count", count);
462  (void) stp_mxmlElementSetAttr(seqnode, "lower-bound", lower_bound);
463  (void) stp_mxmlElementSetAttr(seqnode, "upper-bound", upper_bound);
464
465  stp_free(count);
466  stp_free(lower_bound);
467  stp_free(upper_bound);
468
469  /* Write the curve points into the node content */
470  if (pointcount) /* Is there any data to write? */
471    {
472      for (i = 0; i < pointcount; i++)
473	{
474	  double dval;
475	  char *sval;
476
477	  if ((stp_sequence_get_point(seq, i, &dval)) != 1)
478	    goto error;
479
480	  stp_asprintf(&sval, "%g", dval);
481	  stp_mxmlNewText(seqnode, 1, sval);
482	  stp_free(sval);
483      }
484    }
485  return seqnode;
486
487 error:
488  if (seqnode)
489    stp_mxmlDelete(seqnode);
490  return NULL;
491}
492
493
494#define isfinite_null(x) (1)
495
496/* "Overloaded" functions */
497
498#define DEFINE_DATA_SETTER(t, name, checkfinite)		\
499int								\
500stp_sequence_set_##name##_data(stp_sequence_t *sequence,	\
501                               size_t count, const t *data)	\
502{								\
503  int i;							\
504  CHECK_SEQUENCE(sequence);					\
505  if (count < 2)						\
506    return 0;							\
507								\
508  /* Validate the data before we commit to it. */		\
509  for (i = 0; i < count; i++)					\
510    if ((! checkfinite(data[i])) ||				\
511	data[i] < sequence->blo ||				\
512        data[i] > sequence->bhi)				\
513      return 0;							\
514  stp_sequence_set_size(sequence, count);			\
515  for (i = 0; i < count; i++)					\
516    stp_sequence_set_point(sequence, i, (double) data[i]);	\
517  return 1;							\
518}
519
520DEFINE_DATA_SETTER(float, float, isfinite)
521DEFINE_DATA_SETTER(long, long, isfinite_null)
522DEFINE_DATA_SETTER(unsigned long, ulong, isfinite_null)
523DEFINE_DATA_SETTER(int, int, isfinite_null)
524DEFINE_DATA_SETTER(unsigned int, uint, isfinite_null)
525DEFINE_DATA_SETTER(short, short, isfinite_null)
526DEFINE_DATA_SETTER(unsigned short, ushort, isfinite_null)
527
528#define DEFINE_DATA_ACCESSOR(t, lb, ub, name)				      \
529const t *								      \
530stp_sequence_get_##name##_data(const stp_sequence_t *sequence, size_t *count) \
531{									      \
532  int i;								      \
533  CHECK_SEQUENCE(sequence);						      \
534  if (sequence->blo < (double) lb || sequence->bhi > (double) ub)	      \
535    return NULL;							      \
536  if (!sequence->name##_data)						      \
537    {									      \
538      stp_sequence_t *seq = deconst_sequence(sequence);			      \
539      seq->name##_data = stp_zalloc(sizeof(t) * sequence->size);	      \
540      for (i = 0; i < sequence->size; i++)				      \
541	seq->name##_data[i] = (t) sequence->data[i];			      \
542    }									      \
543  *count = sequence->size;						      \
544  return sequence->name##_data;						      \
545}
546
547#ifndef HUGE_VALF /* ISO constant, from <math.h> */
548#define HUGE_VALF 3.402823466E+38F
549#endif
550
551DEFINE_DATA_ACCESSOR(float, -HUGE_VALF, HUGE_VALF, float)
552DEFINE_DATA_ACCESSOR(long, LONG_MIN, LONG_MAX, long)
553DEFINE_DATA_ACCESSOR(unsigned long, 0, ULONG_MAX, ulong)
554DEFINE_DATA_ACCESSOR(int, INT_MIN, INT_MAX, int)
555DEFINE_DATA_ACCESSOR(unsigned int, 0, UINT_MAX, uint)
556DEFINE_DATA_ACCESSOR(short, SHRT_MIN, SHRT_MAX, short)
557DEFINE_DATA_ACCESSOR(unsigned short, 0, USHRT_MAX, ushort)
558