1/*
2 * "$Id: array.c,v 1.17 2010/08/04 00:33:55 rlk Exp $"
3 *
4 *   Array 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-internal.h"
30#include <gutenprint/gutenprint-intl-internal.h>
31#include <math.h>
32#include <string.h>
33#include <stdlib.h>
34#include <limits.h>
35
36
37struct stp_array
38{
39  stp_sequence_t *data; /* First member, to allow typecasting to sequence. */
40  int x_size;
41  int y_size;
42};
43
44/*
45 * We could do more sanity checks here if we want.
46 */
47#define CHECK_ARRAY(array) STPI_ASSERT(array != NULL, NULL)
48
49static void array_ctor(stp_array_t *array)
50{
51  array->data = stp_sequence_create();
52  stp_sequence_set_size(array->data, array->x_size * array->y_size);
53}
54
55stp_array_t *
56stp_array_create(int x_size, int y_size)
57{
58  stp_array_t *ret;
59  ret = stp_zalloc(sizeof(stp_array_t));
60  ret->x_size = x_size;
61  ret->y_size = y_size;
62  ret->data = NULL;
63  array_ctor(ret);
64  return ret;
65}
66
67
68static void
69array_dtor(stp_array_t *array)
70{
71  if (array->data)
72    stp_sequence_destroy(array->data);
73  memset(array, 0, sizeof(stp_array_t));
74}
75
76void
77stp_array_destroy(stp_array_t *array)
78{
79  CHECK_ARRAY(array);
80  array_dtor(array);
81  stp_free(array);
82}
83
84void
85stp_array_copy(stp_array_t *dest, const stp_array_t *source)
86{
87  CHECK_ARRAY(dest);
88  CHECK_ARRAY(source);
89
90  dest->x_size = source->x_size;
91  dest->y_size = source->y_size;
92  if (dest->data)
93    stp_sequence_destroy(dest->data);
94  dest->data = stp_sequence_create_copy(source->data);
95}
96
97stp_array_t *
98stp_array_create_copy(const stp_array_t *array)
99{
100  stp_array_t *ret;
101  CHECK_ARRAY(array);
102  ret = stp_array_create(0, 0); /* gets freed next */
103  stp_array_copy(ret, array);
104  return ret;
105}
106
107
108void
109stp_array_set_size(stp_array_t *array, int x_size, int y_size)
110{
111  CHECK_ARRAY(array);
112  if (array->data) /* Free old data */
113    stp_sequence_destroy(array->data);
114  array->x_size = x_size;
115  array->y_size = y_size;
116  array->data = stp_sequence_create();
117  stp_sequence_set_size(array->data, array->x_size * array->y_size);
118}
119
120void
121stp_array_get_size(const stp_array_t *array, int *x_size, int *y_size)
122{
123  CHECK_ARRAY(array);
124  *x_size = array->x_size;
125  *y_size = array->y_size;
126  return;
127}
128
129void
130stp_array_set_data(stp_array_t *array, const double *data)
131{
132  CHECK_ARRAY(array);
133  stp_sequence_set_data(array->data, array->x_size * array->y_size,
134			data);
135}
136
137void
138stp_array_get_data(const stp_array_t *array, size_t *size, const double **data)
139{
140  CHECK_ARRAY(array);
141  stp_sequence_get_data(array->data, size, data);
142}
143
144int
145stp_array_set_point(stp_array_t *array, int x, int y, double data)
146{
147  CHECK_ARRAY(array);
148
149  if (((array->x_size * x) + y) >= (array->x_size * array->y_size))
150    return 0;
151
152  return stp_sequence_set_point(array->data, (array->x_size * x) + y, data);}
153
154int
155stp_array_get_point(const stp_array_t *array, int x, int y, double *data)
156{
157  CHECK_ARRAY(array);
158
159  if (((array->x_size * x) + y) >= array->x_size * array->y_size)
160    return 0;
161  return stp_sequence_get_point(array->data,
162				(array->x_size * x) + y, data);
163}
164
165const stp_sequence_t *
166stp_array_get_sequence(const stp_array_t *array)
167{
168  CHECK_ARRAY(array);
169
170  return array->data;
171}
172
173stp_array_t *
174stp_array_create_from_xmltree(stp_mxml_node_t *array)  /* The array node */
175{
176  const char *stmp;                          /* Temporary string */
177  stp_mxml_node_t *child;                       /* Child sequence node */
178  int x_size, y_size;
179  size_t count;
180  stp_sequence_t *seq = NULL;
181  stp_array_t *ret = NULL;
182
183  stmp = stp_mxmlElementGetAttr(array, "x-size");
184  if (stmp)
185    {
186      x_size = (int) strtoul(stmp, NULL, 0);
187    }
188  else
189    {
190      stp_erprintf("stp_array_create_from_xmltree: \"x-size\" missing\n");
191      goto error;
192    }
193  /* Get y-size */
194  stmp = stp_mxmlElementGetAttr(array, "y-size");
195  if (stmp)
196    {
197      y_size = (int) strtoul(stmp, NULL, 0);
198    }
199  else
200    {
201      stp_erprintf("stp_array_create_from_xmltree: \"y-size\" missing\n");
202      goto error;
203    }
204
205  /* Get the sequence data */
206
207  child = stp_mxmlFindElement(array, array, "sequence", NULL, NULL, STP_MXML_DESCEND);
208  if (child)
209    seq = stp_sequence_create_from_xmltree(child);
210
211  if (seq == NULL)
212    goto error;
213
214  ret = stp_array_create(x_size, y_size);
215  if (ret->data)
216    stp_sequence_destroy(ret->data);
217  ret->data = seq;
218
219  count = stp_sequence_get_size(seq);
220  if (count != (x_size * y_size))
221    {
222      stp_erprintf("stp_array_create_from_xmltree: size mismatch between array and sequence\n");
223      goto error;
224    }
225
226  return ret;
227
228 error:
229  stp_erprintf("stp_array_create_from_xmltree: error during array read\n");
230  if (ret)
231    stp_array_destroy(ret);
232  return NULL;
233}
234
235stp_mxml_node_t *
236stp_xmltree_create_from_array(const stp_array_t *array)  /* The array */
237{
238  int x_size, y_size;
239  char *xs, *ys;
240
241  stp_mxml_node_t *arraynode = NULL;
242  stp_mxml_node_t *child = NULL;
243
244  stp_xml_init();
245
246  /* Get array details */
247  stp_array_get_size(array, &x_size, &y_size);
248
249  /* Construct the allocated strings required */
250  stp_asprintf(&xs, "%d", x_size);
251  stp_asprintf(&ys, "%d", y_size);
252
253  arraynode = stp_mxmlNewElement(NULL, "array");
254  stp_mxmlElementSetAttr(arraynode, "x-size", xs);
255  stp_mxmlElementSetAttr(arraynode, "y-size", ys);
256  stp_free(xs);
257  stp_free(ys);
258
259  child = stp_xmltree_create_from_sequence(stp_array_get_sequence(array));
260
261  if (child)
262    stp_mxmlAdd(arraynode, STP_MXML_ADD_AFTER, NULL, child);
263  else
264    {
265      stp_mxmlDelete(arraynode);
266      arraynode = NULL;
267    }
268
269  stp_xml_exit();
270
271  return arraynode;
272}
273