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