1 /* This file is part of the GNU plotutils package. Copyright (C) 1995,
2 1996, 1997, 1998, 1999, 2000, 2005, 2008, Free Software Foundation, Inc.
3
4 The GNU plotutils package is free software. You may redistribute it
5 and/or modify it under the terms of the GNU General Public License as
6 published by the Free Software foundation; either version 2, or (at your
7 option) any later version.
8
9 The GNU plotutils package is distributed in the hope that it will be
10 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with the GNU plotutils package; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
17 Boston, MA 02110-1301, USA. */
18
19 /* This file contains low-level functions used by CGMPlotters. E.g.,
20 _cgm_emit_command_header and _cgm_emit_command_terminator, which begin
21 and end a CGM command. A CGM output file, in either the binary or clear
22 text encoding, is simply a sequence of CGM commands.
23
24 Commands are usually written to the CGMPlotter's output buffer, in which
25 the current page of graphics (i.e. "picture", in CGM jargon) is stored.
26 An output buffer (a plOutbuf) is manipulated by the routines in
27 g_outbuf.c. It includes an array of char, which can grow.
28
29 This file also contains _cgm_emit_integer, _cgm_emit_unsigned_integer,
30 _cgm_emit_point, _cgm_emit_points, _cgm_emit_index, _cgm_emit_enum,
31 _cgm_emit_color_component, and _cgm_emit_string, etc., routines, which
32 write the parameters of the command (i.e., its `data') to the output
33 buffer. The caller invokes zero or more of these routines between a
34 _cgm_emit_command_header .. _cgm_emit_command_terminator pair.
35
36 There is support for specifying a non-default output buffer, i.e., one
37 not associated with the CGMPlotter in the usual way. That is useful for
38 preparing the output file's header and trailer, and per-page headers.
39 See c_defplot.c.
40
41 If the binary CGM encoding is used, CGM's data partitioning scheme is
42 used. As a command and its arguments are emitted, variables that play a
43 role in implementing the data partitioning scheme are updated via
44 pointers. These include the number of data bytes written, and the total
45 number of bytes written as part of the command. The caller should
46 initialize these variables to zero at the beginning of the CGM command.
47
48 There is support for turning off data partitioning. _cgm_emit_integer()
49 and the other commands for emitting command parameters support a
50 `no_partitioning' flag argument. This is useful because some CGM
51 commands take a `structured data record' argument. An SDR is
52 essentially a string [a sequence of octets], which may be emitted by
53 calling _cgm_emit_string(), like an ordinary string. However, an SDR
54 must first be formed by calling a sequence of zero or more such commands
55 as _cgm_emit_integer() etc., with output to a plOutbuf (with data
56 partitioning turned off, if the binary encoding is used). */
57
58 /* Note: in the binary encoding is used, we go to extremes to make the
59 written-out CGM file portable. E.g., we hand-craft a big-endian
60 2's-complement representation (the CGM standard) for each integer or
61 unsigned integer, and write each octet individually to the output buffer
62 as an unsigned char or char. We don't assume the system represents
63 integers using 2's complement. We do assume that casting an unsigned
64 char to a char doesn't change the bit pattern.
65
66 The number of octets used in the CGM representation of an integer or
67 unsigned integer, CGM_BINARY_BYTES_PER_INTEGER, is set in extern.h. It
68 should NOT be greater than the number of octets used in the system
69 representation of an unsigned int; see comment below. On nearly all
70 systems that GNU supports, this maximum value for
71 CGM_BINARY_BYTES_PER_INTEGER is 4 (it is never 2).
72
73 Many CGM files use CGM_BINARY_BYTES_PER_INTEGER = 2. In some old,
74 noncompliant CGM parsers this value is hard-coded, even though it
75 shouldn't be. So use higher values (e.g., 3 and 4) with caution. The
76 "CGM Handbook" says the use of 3, rather than 2 or 4, is very rare. */
77
78 #include "sys-defines.h"
79 #include "extern.h"
80
81 /* In the binary encoding, if the data section, i.e., the list of
82 parameters for the command, contains more than 30 bytes, it is written
83 in partitioned format. This is the maximum number of data bytes we
84 place in each block of the partition. Could be as large as 32767, but
85 we keep it small to avoid a buffer overrun (see comment in g_outbuf.c). */
86 #define CGM_BINARY_DATA_BYTES_PER_PARTITION 3000
87
88 /* How to recognize the beginning of a new block of the partition
89 (*data_byte_count is the running count of emitted data bytes,
90 initialized by the caller to zero, and updated throughout the CGM
91 command). */
92 #define CGM_BINARY_DATA_PARTITION_BEGINS(data_len, data_byte_count) \
93 (((data_len) > 30) && ((*(data_byte_count)) % CGM_BINARY_DATA_BYTES_PER_PARTITION == 0))
94
95 /* forward references */
96 static void cgm_emit_partition_control_word (plOutbuf *outbuf, int data_len, const int *data_byte_count, int *byte_count);
97 static void double_to_ieee_single_precision (double d, unsigned char output[4]);
98 static void int_to_cgm_int (int n, unsigned char *cgm_int, int octets_per_cgm_int);
99 static void unsigned_int_to_cgm_unsigned_int (unsigned int n, unsigned char *cgm_unsigned_int, int octets_per_cgm_unsigned_int);
100
101
102 /* Write the header of a CGM command.
103
104 In the clear text encoding, a string (the `op code') is written.
105
106 In the binary encoding, a 2-byte word is written: it specifies the CGM
107 element class and element ID, and `data_len': the number of data bytes
108 that the caller will write, by subsequently calling the functions that
109 emit command arguments.
110
111 `data_len' includes CGM_BINARY_BYTES_PER_INTEGER bytes for an integer,
112 and twice that for a point; two bytes for an index or enumerative, and
113 four bytes for a real. For a string, the number of data bytes can be
114 computed from the CGM_BINARY_BYTES_PER_STRING() macro. The caller
115 should initialize *byte_count to zero, and also *data_byte_count (the
116 latter is updated by the argument-emitting functions). */
117
118 void
_cgm_emit_command_header(plOutbuf * outbuf,int cgm_encoding,int element_class,int id,int data_len,int * byte_count,const char * op_code)119 _cgm_emit_command_header (plOutbuf *outbuf, int cgm_encoding, int element_class, int id, int data_len, int *byte_count, const char *op_code)
120 {
121 switch (cgm_encoding)
122 {
123 case CGM_ENCODING_BINARY:
124 default:
125 {
126 int temp;
127
128 if (data_len > 30)
129 data_len = 31; /* set all 5 bits; will partition the data */
130
131 temp = (element_class & 017) << 4; /* 4 bits, shifted up by 4 */
132 temp |= (id >> 3) & 017; /* top 4 of 7 bits, shifted down by 3 */
133 outbuf->point[0] = (char)(unsigned char)temp;
134 temp = (id & 0177) << 5; /* lower 3 of 7 bits, shifted up by 5 */
135 temp |= (data_len & 037); /* 5 bits, not shifted */
136 outbuf->point[1] = (char)(unsigned char)temp;
137 _update_buffer_by_added_bytes (outbuf, 2);
138 (*byte_count) += 2;
139 }
140 break;
141
142 case CGM_ENCODING_CHARACTER: /* not supported */
143 break;
144
145 case CGM_ENCODING_CLEAR_TEXT:
146 sprintf (outbuf->point, "%s", op_code);
147 _update_buffer (outbuf);
148 break;
149 }
150 }
151
152 /* In the binary encoding, this is called automatically at the beginning of
153 each data partition, if a partitioned parameter list is used. It writes
154 a 2-byte big-endian control word that specifies how many data bytes the
155 partition will contain. It may set a continuation flag in the control
156 word, to indicate that another data partition will follow. */
157
158 static void
cgm_emit_partition_control_word(plOutbuf * outbuf,int data_len,const int * data_byte_count,int * byte_count)159 cgm_emit_partition_control_word (plOutbuf *outbuf, int data_len, const int *data_byte_count, int *byte_count)
160 {
161 int bytes_remaining = data_len - (*data_byte_count);
162 int bytes_in_partition;
163 unsigned int control_word;
164
165 if (bytes_remaining > CGM_BINARY_DATA_BYTES_PER_PARTITION)
166 {
167 bytes_in_partition = CGM_BINARY_DATA_BYTES_PER_PARTITION;
168 control_word = 1 << 15; /* set continuation flag */
169 }
170 else
171 {
172 bytes_in_partition = bytes_remaining;
173 control_word = 0;
174 }
175 control_word |= (unsigned int)bytes_in_partition;
176
177 /* write control word, big-endian */
178 outbuf->point[0] = (char)(unsigned char)((control_word >> 8) & 0377);
179 outbuf->point[1] = (char)(unsigned char)(control_word & 0377);
180 _update_buffer_by_added_bytes (outbuf, 2);
181 (*byte_count) += 2;
182 }
183
184 /* Encode a (signed) integer in binary CGM format. This is a big-endian
185 2's complement format, with k=8*octets_per_cgm_int bits per integer.
186 The signed integer is clamped to the range -(2^(k-1) - 1) .. (2^(k-1)-1)
187 and split into octets, with attention paid to the sign bit.
188
189 We do not assume the system representation of integers is a 2's
190 complement format. We do assume that the system uses at least k octets
191 per unsigned int.
192
193 The octets are returned in an array of unsigned chars. Since any of our
194 output buffers contains an array of char, we'll be assuming that the bit
195 pattern of chars and unsigned chars is the same, so that we can cast
196 unsigned chars to chars with impunity. */
197
198 static void
int_to_cgm_int(int n,unsigned char * cgm_int,int octets_per_cgm_int)199 int_to_cgm_int (int n, unsigned char *cgm_int, int octets_per_cgm_int)
200 {
201 int max_int, i;
202 unsigned int u;
203 bool negative = false;
204
205 /* clamp integer; we assume here that the system uses at least
206 octest_per_cgm_int octets per unsigned int, i.e. that the system
207 precision is at least as great as the CGM precision */
208 max_int = 0;
209 for (i = 0; i < (8 * octets_per_cgm_int - 1); i++)
210 max_int += (1 << i);
211
212 if (n > max_int)
213 n = max_int;
214 else if (n < -max_int)
215 n = -max_int;
216
217 if (n < 0)
218 {
219 int temp;
220
221 negative = true;
222 temp = -(n + 1);
223 u = (unsigned int)(max_int - temp); /* compute 2's complement */
224 }
225 else
226 u = (unsigned int)n;
227
228 for (i = 0; i < octets_per_cgm_int; i++)
229 {
230 unsigned char v;
231
232 v = 0xff & (u >> (8 * ((octets_per_cgm_int - 1) - i)));
233 if (i == 0 && negative)
234 v |= 0x80;
235 cgm_int[i] = v;
236 }
237 }
238
239 /* similar to the preceding, but for unsigned ints rather than signed ints */
240
241 static void
unsigned_int_to_cgm_unsigned_int(unsigned int n,unsigned char * cgm_unsigned_int,int octets_per_cgm_unsigned_int)242 unsigned_int_to_cgm_unsigned_int (unsigned int n, unsigned char *cgm_unsigned_int, int octets_per_cgm_unsigned_int)
243 {
244 unsigned int max_unsigned_int;
245 int i;
246
247 /* clamp unsigned integer; we assume here that the system uses at least
248 octets_per_cgm_unsigned_int octets per unsigned int, i.e. that the
249 system precision is at least as great as the CGM precision */
250 max_unsigned_int = 0;
251 for (i = 0; i < (8 * octets_per_cgm_unsigned_int); i++)
252 max_unsigned_int += (1 << i);
253
254 if (n > max_unsigned_int)
255 n = max_unsigned_int;
256
257 for (i = 0; i < octets_per_cgm_unsigned_int; i++)
258 {
259 unsigned char v;
260
261 v = 0xff & (n >> (8 * ((octets_per_cgm_unsigned_int - 1) - i)));
262 cgm_unsigned_int[i] = v;
263 }
264 }
265
266 /* Write a (signed) integer in CGM format. In the binary encoding,
267 CGM_BINARY_BYTES_PER_INTEGER bytes are written. In CGM files the
268 default value for that parameter (defined in extern.h) is 2, but it can
269 be increased. */
270
271 void
_cgm_emit_integer(plOutbuf * outbuf,bool no_partitioning,int cgm_encoding,int x,int data_len,int * data_byte_count,int * byte_count)272 _cgm_emit_integer (plOutbuf *outbuf, bool no_partitioning, int cgm_encoding, int x, int data_len, int *data_byte_count, int *byte_count)
273 {
274 int i;
275 unsigned char cgm_int[CGM_BINARY_BYTES_PER_INTEGER];
276
277 switch (cgm_encoding)
278 {
279 case CGM_ENCODING_BINARY:
280 default:
281 int_to_cgm_int (x, cgm_int, CGM_BINARY_BYTES_PER_INTEGER);
282 for (i = 0; i < CGM_BINARY_BYTES_PER_INTEGER; i++)
283 {
284 if (no_partitioning == false
285 && CGM_BINARY_DATA_PARTITION_BEGINS(data_len, data_byte_count))
286 cgm_emit_partition_control_word (outbuf, data_len, data_byte_count, byte_count);
287
288 *(outbuf->point) = (char)(cgm_int[i]);
289 _update_buffer_by_added_bytes (outbuf, 1);
290 (*data_byte_count)++;
291 (*byte_count)++;
292 }
293 break;
294
295 case CGM_ENCODING_CHARACTER: /* not supported */
296 break;
297
298 case CGM_ENCODING_CLEAR_TEXT:
299 sprintf (outbuf->point, " %d", x);
300 _update_buffer (outbuf);
301 break;
302 }
303 }
304
305 /* similar to the preceding, but writes an unsigned integer rather than a
306 signed integer. */
307
308 void
_cgm_emit_unsigned_integer(plOutbuf * outbuf,bool no_partitioning,int cgm_encoding,unsigned int x,int data_len,int * data_byte_count,int * byte_count)309 _cgm_emit_unsigned_integer (plOutbuf *outbuf, bool no_partitioning, int cgm_encoding, unsigned int x, int data_len, int *data_byte_count, int *byte_count)
310 {
311 int i;
312 unsigned char cgm_unsigned_int[CGM_BINARY_BYTES_PER_INTEGER];
313
314 switch (cgm_encoding)
315 {
316 case CGM_ENCODING_BINARY:
317 default:
318 unsigned_int_to_cgm_unsigned_int (x, cgm_unsigned_int, CGM_BINARY_BYTES_PER_INTEGER);
319 for (i = 0; i < CGM_BINARY_BYTES_PER_INTEGER; i++)
320 {
321 if (no_partitioning == false
322 && CGM_BINARY_DATA_PARTITION_BEGINS(data_len, data_byte_count))
323 cgm_emit_partition_control_word (outbuf, data_len, data_byte_count, byte_count);
324
325 *(outbuf->point) = (char)(cgm_unsigned_int[i]);
326 _update_buffer_by_added_bytes (outbuf, 1);
327 (*data_byte_count)++;
328 (*byte_count)++;
329 }
330 break;
331
332 case CGM_ENCODING_CHARACTER: /* not supported */
333 break;
334
335 case CGM_ENCODING_CLEAR_TEXT:
336 sprintf (outbuf->point, " %u", x);
337 _update_buffer (outbuf);
338 break;
339 }
340 }
341
342 /* similar to the preceding, but writes an `8-bit' unsigned integer (an
343 unsigned integer in the range 0.255) as a single byte. */
344
345 void
_cgm_emit_unsigned_integer_8bit(plOutbuf * outbuf,bool no_partitioning,int cgm_encoding,unsigned int x,int data_len,int * data_byte_count,int * byte_count)346 _cgm_emit_unsigned_integer_8bit (plOutbuf *outbuf, bool no_partitioning, int cgm_encoding, unsigned int x, int data_len, int *data_byte_count, int *byte_count)
347 {
348 /* clamp to 0..255 */
349 if (x > (unsigned int)255)
350 x = (unsigned int)255;
351
352 switch (cgm_encoding)
353 {
354 case CGM_ENCODING_BINARY:
355 default:
356 if (no_partitioning == false
357 && CGM_BINARY_DATA_PARTITION_BEGINS(data_len, data_byte_count))
358 cgm_emit_partition_control_word (outbuf, data_len, data_byte_count, byte_count);
359
360 *(outbuf->point) = (char)(unsigned char)x;
361 _update_buffer_by_added_bytes (outbuf, 1);
362 (*data_byte_count)++;
363 (*byte_count)++;
364 break;
365
366 case CGM_ENCODING_CHARACTER: /* not supported */
367 break;
368
369 case CGM_ENCODING_CLEAR_TEXT:
370 sprintf (outbuf->point, " %u", x);
371 _update_buffer (outbuf);
372 break;
373 }
374 }
375
376 /* Write a point, i.e. a pair of (signed) integers, in CGM format. In the
377 binary encoding, 2 * CGM_BINARY_BYTES_PER_INTEGER bytes are written. */
378
379 void
_cgm_emit_point(plOutbuf * outbuf,bool no_partitioning,int cgm_encoding,int x,int y,int data_len,int * data_byte_count,int * byte_count)380 _cgm_emit_point (plOutbuf *outbuf, bool no_partitioning, int cgm_encoding, int x, int y, int data_len, int *data_byte_count, int *byte_count)
381 {
382 int i;
383 unsigned char cgm_int[CGM_BINARY_BYTES_PER_INTEGER];
384
385 switch (cgm_encoding)
386 {
387 case CGM_ENCODING_BINARY:
388 default:
389 int_to_cgm_int (x, cgm_int, CGM_BINARY_BYTES_PER_INTEGER);
390 for (i = 0; i < CGM_BINARY_BYTES_PER_INTEGER; i++)
391 {
392 if (no_partitioning == false
393 && CGM_BINARY_DATA_PARTITION_BEGINS(data_len, data_byte_count))
394 cgm_emit_partition_control_word (outbuf, data_len, data_byte_count, byte_count);
395
396 *(outbuf->point) = (char)(cgm_int[i]);
397 _update_buffer_by_added_bytes (outbuf, 1);
398 (*data_byte_count)++;
399 (*byte_count)++;
400 }
401 int_to_cgm_int (y, cgm_int, CGM_BINARY_BYTES_PER_INTEGER);
402 for (i = 0; i < CGM_BINARY_BYTES_PER_INTEGER; i++)
403 {
404 if (no_partitioning == false
405 && CGM_BINARY_DATA_PARTITION_BEGINS(data_len, data_byte_count))
406 cgm_emit_partition_control_word (outbuf, data_len, data_byte_count, byte_count);
407
408 *(outbuf->point) = (char)(cgm_int[i]);
409 _update_buffer_by_added_bytes (outbuf, 1);
410 (*data_byte_count)++;
411 (*byte_count)++;
412 }
413 break;
414
415 case CGM_ENCODING_CHARACTER: /* not supported */
416 break;
417
418 case CGM_ENCODING_CLEAR_TEXT:
419 sprintf (outbuf->point, " (%d, %d)", x, y);
420 _update_buffer (outbuf);
421 break;
422 }
423 }
424
425 /* Write a list of points, i.e. a list of pairs of (signed) integers, in
426 CGM format. */
427
428 void
_cgm_emit_points(plOutbuf * outbuf,bool no_partitioning,int cgm_encoding,const int * x,const int * y,int npoints,int data_len,int * data_byte_count,int * byte_count)429 _cgm_emit_points (plOutbuf *outbuf, bool no_partitioning, int cgm_encoding, const int *x, const int *y, int npoints, int data_len, int *data_byte_count, int *byte_count)
430 {
431 int i, j;
432 unsigned char cgm_int[CGM_BINARY_BYTES_PER_INTEGER];
433
434 switch (cgm_encoding)
435 {
436 case CGM_ENCODING_BINARY:
437 default:
438 for (j = 0; j < npoints; j++)
439 {
440 int_to_cgm_int (x[j], cgm_int, CGM_BINARY_BYTES_PER_INTEGER);
441 for (i = 0; i < CGM_BINARY_BYTES_PER_INTEGER; i++)
442 {
443 if (no_partitioning == false
444 && CGM_BINARY_DATA_PARTITION_BEGINS(data_len, data_byte_count))
445 cgm_emit_partition_control_word (outbuf, data_len, data_byte_count, byte_count);
446
447 *(outbuf->point) = (char)(cgm_int[i]);
448 _update_buffer_by_added_bytes (outbuf, 1);
449 (*data_byte_count)++;
450 (*byte_count)++;
451 }
452 int_to_cgm_int (y[j], cgm_int, CGM_BINARY_BYTES_PER_INTEGER);
453 for (i = 0; i < CGM_BINARY_BYTES_PER_INTEGER; i++)
454 {
455 if (no_partitioning == false
456 && CGM_BINARY_DATA_PARTITION_BEGINS(data_len, data_byte_count))
457 cgm_emit_partition_control_word (outbuf, data_len, data_byte_count, byte_count);
458
459 *(outbuf->point) = (char)(cgm_int[i]);
460 _update_buffer_by_added_bytes (outbuf, 1);
461 (*data_byte_count)++;
462 (*byte_count)++;
463 }
464 }
465 break;
466
467 case CGM_ENCODING_CHARACTER: /* not supported */
468 break;
469
470 case CGM_ENCODING_CLEAR_TEXT:
471 for (i = 0; i < npoints; i++)
472 {
473 sprintf (outbuf->point, " (%d, %d)", x[i], y[i]);
474 _update_buffer (outbuf);
475 }
476 break;
477 }
478 }
479
480 /* Write an `enumerative', in CGM format. In the binary encoding, 2 bytes
481 are written. This is just like _cgm_emit_integer, except that the
482 precision is fixed at 16 bits. In the clear text encoding, a text
483 string is written. */
484
485 void
_cgm_emit_enum(plOutbuf * outbuf,bool no_partitioning,int cgm_encoding,int x,int data_len,int * data_byte_count,int * byte_count,const char * text_string)486 _cgm_emit_enum (plOutbuf *outbuf, bool no_partitioning, int cgm_encoding, int x, int data_len, int *data_byte_count, int *byte_count, const char *text_string)
487 {
488 int i;
489 unsigned char cgm_int[2];
490
491 switch (cgm_encoding)
492 {
493 case CGM_ENCODING_BINARY:
494 default:
495 int_to_cgm_int (x, cgm_int, 2);
496 for (i = 0; i < 2; i++)
497 {
498 if (no_partitioning == false
499 && CGM_BINARY_DATA_PARTITION_BEGINS(data_len, data_byte_count))
500 cgm_emit_partition_control_word (outbuf, data_len, data_byte_count, byte_count);
501
502 *(outbuf->point) = (char)(cgm_int[i]);
503 _update_buffer_by_added_bytes (outbuf, 1);
504 (*data_byte_count)++;
505 (*byte_count)++;
506 }
507 break;
508
509 case CGM_ENCODING_CHARACTER: /* not supported */
510 break;
511
512 case CGM_ENCODING_CLEAR_TEXT:
513 sprintf (outbuf->point, " %s", text_string);
514 _update_buffer (outbuf);
515 break;
516 }
517 }
518
519 /* Write an `index' in CGM format. In the binary encoding, 2 bytes are
520 written. This is just like _cgm_emit_integer, except that we fix the
521 precision at 16 bits (this could be changed, but according to the "CGM
522 Handbook", using any other index precision is very rare).
523
524 In c_defplot.c, we use this routine also for writing 2-byte integers or
525 VDC integers (necessary before we reset the integer and VDC integer
526 precisions). */
527
528 void
_cgm_emit_index(plOutbuf * outbuf,bool no_partitioning,int cgm_encoding,int x,int data_len,int * data_byte_count,int * byte_count)529 _cgm_emit_index (plOutbuf *outbuf, bool no_partitioning, int cgm_encoding, int x, int data_len, int *data_byte_count, int *byte_count)
530 {
531 int i;
532 unsigned char cgm_int[2];
533
534 switch (cgm_encoding)
535 {
536 case CGM_ENCODING_BINARY:
537 default:
538 int_to_cgm_int (x, cgm_int, 2);
539 for (i = 0; i < 2; i++)
540 {
541 if (no_partitioning == false
542 && CGM_BINARY_DATA_PARTITION_BEGINS(data_len, data_byte_count))
543 cgm_emit_partition_control_word (outbuf, data_len, data_byte_count, byte_count);
544
545 *(outbuf->point) = (char)(cgm_int[i]);
546 _update_buffer_by_added_bytes (outbuf, 1);
547 (*data_byte_count)++;
548 (*byte_count)++;
549 }
550 break;
551
552 case CGM_ENCODING_CHARACTER: /* not supported */
553 break;
554
555 case CGM_ENCODING_CLEAR_TEXT:
556 sprintf (outbuf->point, " %d", x);
557 _update_buffer (outbuf);
558 break;
559 }
560 }
561
562 /* Write a `color component' in CGM format. In the binary encoding,
563 CGM_BINARY_BYTES_PER_COLOR_COMPONENT bytes are written. Valid values
564 for that parameter (set in extern.h) are 1, 2, 3, 4, but our code in
565 c_color.c supports only 1 or 2, i.e. 24-bit color or 48-bit color. */
566
567 void
_cgm_emit_color_component(plOutbuf * outbuf,bool no_partitioning,int cgm_encoding,unsigned int x,int data_len,int * data_byte_count,int * byte_count)568 _cgm_emit_color_component (plOutbuf *outbuf, bool no_partitioning, int cgm_encoding, unsigned int x, int data_len, int *data_byte_count, int *byte_count)
569 {
570 int i;
571 unsigned char cgm_unsigned_int[CGM_BINARY_BYTES_PER_COLOR_COMPONENT];
572
573 switch (cgm_encoding)
574 {
575 case CGM_ENCODING_BINARY:
576 default:
577 unsigned_int_to_cgm_unsigned_int (x, cgm_unsigned_int,
578 CGM_BINARY_BYTES_PER_COLOR_COMPONENT);
579 for (i = 0; i < CGM_BINARY_BYTES_PER_COLOR_COMPONENT; i++)
580 {
581 if (no_partitioning == false
582 && CGM_BINARY_DATA_PARTITION_BEGINS(data_len, data_byte_count))
583 cgm_emit_partition_control_word (outbuf, data_len, data_byte_count, byte_count);
584
585 *(outbuf->point) = (char)(cgm_unsigned_int[i]);
586 _update_buffer_by_added_bytes (outbuf, 1);
587 (*data_byte_count)++;
588 (*byte_count)++;
589 }
590 break;
591
592 case CGM_ENCODING_CHARACTER: /* not supported */
593 break;
594
595 case CGM_ENCODING_CLEAR_TEXT:
596 sprintf (outbuf->point, " %u", x);
597 _update_buffer (outbuf);
598 break;
599 }
600 }
601
602 /* Write a real quantity. In the binary encoding, the default CGM
603 fixed-point format is used. That is 32 bits, with 16 bits for integer
604 part [including sign bit] and 16 for added fraction in range [0,1);
605 numbers from -32767.0 to 32768.0- may be represented. In the clear text
606 encoding, a conventional representation is used. */
607
608 void
_cgm_emit_real_fixed_point(plOutbuf * outbuf,bool no_partitioning,int cgm_encoding,double x,int data_len,int * data_byte_count,int * byte_count)609 _cgm_emit_real_fixed_point (plOutbuf *outbuf, bool no_partitioning, int cgm_encoding, double x, int data_len, int *data_byte_count, int *byte_count)
610 {
611 int x_floor;
612 unsigned int x_frac;
613 int i;
614 unsigned char cgm_int[2], cgm_unsigned_int[2];
615
616 /* clamp to range [-32767.0,32767.0] */
617 if (x < -32767.0)
618 x = -32767.0;
619 else if (x > 32767.0)
620 x = 32767.0;
621
622 x_floor = (x >= 0.0 ? (int)x : -1 - ((int)(-x)));
623 x_frac = (unsigned int)(65536 * (x - x_floor));
624
625 switch (cgm_encoding)
626 {
627 case CGM_ENCODING_BINARY:
628 default:
629 int_to_cgm_int (x_floor, cgm_int, 2);
630 for (i = 0; i < 2; i++)
631 {
632 if (no_partitioning == false
633 && CGM_BINARY_DATA_PARTITION_BEGINS(data_len, data_byte_count))
634 cgm_emit_partition_control_word (outbuf, data_len, data_byte_count, byte_count);
635
636 *(outbuf->point) = (char)(cgm_int[i]);
637 _update_buffer_by_added_bytes (outbuf, 1);
638 (*data_byte_count)++;
639 (*byte_count)++;
640 }
641 unsigned_int_to_cgm_unsigned_int (x_frac, cgm_unsigned_int, 2);
642 for (i = 0; i < 2; i++)
643 {
644 if (no_partitioning == false
645 && CGM_BINARY_DATA_PARTITION_BEGINS(data_len, data_byte_count))
646 cgm_emit_partition_control_word (outbuf, data_len, data_byte_count, byte_count);
647
648 *(outbuf->point) = (char)(cgm_unsigned_int[i]);
649 _update_buffer_by_added_bytes (outbuf, 1);
650 (*data_byte_count)++;
651 (*byte_count)++;
652 }
653 break;
654
655 case CGM_ENCODING_CHARACTER: /* not supported */
656 break;
657
658 case CGM_ENCODING_CLEAR_TEXT:
659 if (x != 0.0)
660 sprintf (outbuf->point, " %.8f", x);
661 else
662 sprintf (outbuf->point, " 0.0");
663 _update_buffer (outbuf);
664 break;
665 }
666 }
667
668 /* Express a real number (a C `double') in IEEE single precision format:
669 32 bits, including 1 sign bit, 8 exponent bits, and 23 mantissa bits,
670 split into 4 octets, i.e. bytes, in big-endian order.
671
672 The octets are returned in an array of unsigned chars. Since any of our
673 output buffers contains an array of char, we'll be assuming that the bit
674 pattern of chars and unsigned chars is the same, so that we can cast
675 unsigned chars to chars with impunity. */
676
677 static void
double_to_ieee_single_precision(double d,unsigned char output[4])678 double_to_ieee_single_precision (double d, unsigned char output[4])
679 {
680 double min_magnitude, max_magnitude, tmp_power, max_power;
681 bool got_a_bit;
682 int i, j;
683 int sign_bit;
684 int mantissa_bits[23]; /* leading `1' omitted */
685 int exponent_bits[8];
686 int biased_exponent = 0; /* usually 1..254, meaning 1-127..254-127 */
687 int bits[256]; /* as indices, 1..254 are meaningful */
688 int output_bits[32];
689
690 /* compute min, max magnitudes we'll produce */
691
692 /* minimum = 2^(1-127) = 2^(-126). This is the minimum non-subnormalized
693 IEEE single-precision floating point number. */
694 min_magnitude = 1.0;
695 for (i = 0; i < 127-1; i++)
696 min_magnitude /= 2;
697
698 /* maximum = 2^(255-127) [1.0 - 2^(-24)] = 2^128 - 2^104
699 = 1.11111111111111111111111 * 2^(254-127)
700 = 1.11111111111111111111111 * 2^127
701 This is the maximum IEEE single-precision floating point number. */
702 tmp_power = 1.0;
703 max_magnitude = 0.0;
704 for (i = 0; i <= 254-127; i++)
705 {
706 if (i >= 104)
707 max_magnitude += tmp_power;
708 tmp_power *= 2;
709 }
710
711 /* replace NaN by maximum positive value */
712 if (d != d)
713 d = max_magnitude;
714
715 /* extract sign bit */
716 if (d < 0.0)
717 {
718 sign_bit = 1;
719 d = -d;
720 }
721 else
722 sign_bit = 0;
723
724 /* if nonzero, clamp to allowed range */
725 if (d != 0.0 && d < min_magnitude)
726 d = min_magnitude;
727 else if (d > max_magnitude)
728 d = max_magnitude;
729
730 /* compute max power of two that can occur in binary expansion,
731 i.e. 2^(254-127) = 2^127 */
732 max_power = 1.0;
733 for (i = 0; i < 254-127; i++)
734 max_power *= 2;
735
736 /* compute bits array; location of first `1' will be biased exponent */
737 for (i = 0; i < 256; i++)
738 bits[i] = 0;
739 got_a_bit = false;
740 for (i = 254, tmp_power = max_power; i >= 1; i--, tmp_power /= 2)
741 if (d >= tmp_power)
742 {
743 if (got_a_bit == false)
744 {
745 biased_exponent = i; /* will be in range 1..254, if set */
746 got_a_bit = true;
747 }
748 bits[i] = 1;
749 d -= tmp_power;
750 }
751 if (got_a_bit == false)
752 /* d = 0.0, use bogus value for biased exponent */
753 biased_exponent = 0;
754
755 /* extract mantissa bits: in bits array, they start after first `1' */
756 for (j = 0; j < 23; j++)
757 mantissa_bits[j] = 0;
758 if (got_a_bit == true)
759 for (i = biased_exponent - 1, j = 0; i >= 1 && j < 23; i--, j++)
760 mantissa_bits[j] = bits[i];
761
762 /* extract exponent bits; exponent is in range 0..254 */
763 for (j = 7; j >= 0; j--)
764 {
765 exponent_bits[j] = biased_exponent % 2;
766 biased_exponent /= 2;
767 }
768
769 /* construct output array of 32 bits */
770 output_bits[0] = sign_bit;
771 for (j = 0; j < 8; j++)
772 output_bits[j + 1] = exponent_bits[j];
773 for (j = 0; j < 23; j++)
774 output_bits[j + 9] = mantissa_bits[j];
775
776 for (j = 0; j < 4; j++)
777 output[j] = (unsigned char)0;
778 for (j = 0; j < 32; j++)
779 if (output_bits[j] == 1)
780 output[j / 8] |= (1 << ((31 - j) % 8));
781 }
782
783 /* Write a real quantity. Like the _cgm_emit_real_fixed_point, but in the
784 binary encoding, rather than a fixed-point format, a floating-point
785 format is used. In particular, IEEE single-precision format, occupying
786 32 bits; split into octets in big-endian order.
787
788 A CGMPlotter calls this function only to write a mandatory `scaling
789 factor' that is probably bogus. See c_defplot.c. */
790
791 void
_cgm_emit_real_floating_point(plOutbuf * outbuf,bool no_partitioning,int cgm_encoding,double x,int data_len,int * data_byte_count,int * byte_count)792 _cgm_emit_real_floating_point (plOutbuf *outbuf, bool no_partitioning, int cgm_encoding, double x, int data_len, int *data_byte_count, int *byte_count)
793 {
794 int i;
795 unsigned char cp[4];
796
797 switch (cgm_encoding)
798 {
799 case CGM_ENCODING_BINARY:
800 default:
801 double_to_ieee_single_precision (x, cp);
802 for (i = 0; i < 4; i++)
803 {
804 if (no_partitioning == false
805 && CGM_BINARY_DATA_PARTITION_BEGINS(data_len, data_byte_count))
806 cgm_emit_partition_control_word (outbuf, data_len, data_byte_count, byte_count);
807 *(outbuf->point) = (char)(cp[i]);
808 _update_buffer_by_added_bytes (outbuf, 1);
809 (*data_byte_count)++;
810 (*byte_count)++;
811 }
812 break;
813
814 case CGM_ENCODING_CHARACTER: /* not supported */
815 break;
816
817 case CGM_ENCODING_CLEAR_TEXT:
818 sprintf (outbuf->point, " %.8f", x);
819 _update_buffer (outbuf);
820 break;
821 }
822 }
823
824 /* Write a string, in CGM format.
825
826 In the binary encoding, string encoding depends on string length. (1)
827 If length <= 254 bytes, the length is prepended to the string, as a
828 single byte. (2) If length >= 255 bytes, the encoding begins with a
829 byte equal to 255. Then there is a sixteen-bit word containing a length
830 (up to 32767) and a continuation flag, followed by data bytes; the two
831 of them constitute a `string partition', which may be repeated
832 arbitrarily many times. We use at most CGM_STRING_PARTITION_SIZE data
833 bytes in a partition, rather than 32767, to avoid buffer overrun; see
834 comment above. The total byte length of the encoded string, if
835 string_length=original length, equals
836 CGM_BINARY_BYTES_PER_STRING(string_length). This macro is defined in
837 extern.h.
838
839 In the clear text encoding, we surround the string by quotes, and escape
840 any quote that it contains by doubling it. We use single quotes unless
841 the `use_double_quotes' flag is set. */
842
843 void
_cgm_emit_string(plOutbuf * outbuf,bool no_partitioning,int cgm_encoding,const char * s,int string_length,bool use_double_quotes,int data_len,int * data_byte_count,int * byte_count)844 _cgm_emit_string (plOutbuf *outbuf, bool no_partitioning, int cgm_encoding, const char *s, int string_length, bool use_double_quotes, int data_len, int *data_byte_count, int *byte_count)
845 {
846 int i, encoded_string_length;
847 const char *sp = s;
848 char *t, *tp, c;
849
850 switch (cgm_encoding)
851 {
852 case CGM_ENCODING_BINARY:
853 default:
854 {
855 #if 0
856 fprintf (stderr, "cgm_emit_string(), length=%d\n", string_length);
857 for (i = 0; i < string_length; i++)
858 putc (s[i], stderr);
859 putc ('\n', stderr);
860 #endif
861
862 /* first, encode the string */
863
864 encoded_string_length = CGM_BINARY_BYTES_PER_STRING(string_length);
865 tp = t = (char *)_pl_xmalloc (encoded_string_length * sizeof(char));
866
867 if (string_length <= 254)
868 {
869 /* begin with `count' byte, follow by original string */
870 *tp++ = (char)(unsigned char)string_length;
871 for (i = 0; i < string_length; i++)
872 *tp++ = *sp++;
873 }
874 else
875 {
876 /* first byte is `255' */
877 *tp++ = (char)255;
878
879 /* copy data bytes, with string partition headers interpolated
880 as needed; `i' counts data bytes copied */
881 for (i = 0; i < string_length; i++, sp++)
882 {
883 if (i % CGM_STRING_PARTITION_SIZE == 0)
884 /* write two-byte string partition header */
885 {
886 int bytes_remaining = string_length - i;
887 int string_header_word;
888
889 if (bytes_remaining <= CGM_STRING_PARTITION_SIZE)
890 string_header_word = bytes_remaining;
891 else
892 /* must continue; set continuation flag */
893 {
894 string_header_word = (1 << 15);
895 string_header_word |= CGM_STRING_PARTITION_SIZE;
896 }
897 /* write string partition header word, big-endian */
898 *tp++ = (char)((string_header_word >> 8) & 0377);
899 *tp++ = (char)(string_header_word & 0377);
900 }
901
902 /* copy byte */
903 *tp++ = *sp;
904 }
905 }
906
907 /* copy encoded string to output buffer; it may require more than
908 one data partition */
909 for (i = 0; i < encoded_string_length; i++)
910 {
911 if (no_partitioning == false
912 && CGM_BINARY_DATA_PARTITION_BEGINS(data_len, data_byte_count))
913 cgm_emit_partition_control_word (outbuf, data_len, data_byte_count, byte_count);
914 *(outbuf->point) = t[i];
915 _update_buffer_by_added_bytes (outbuf, 1);
916 (*data_byte_count)++;
917 (*byte_count)++;
918 }
919
920 /* free encoded string */
921 free (t);
922 }
923 break;
924
925 case CGM_ENCODING_CHARACTER: /* not supported */
926 break;
927
928 case CGM_ENCODING_CLEAR_TEXT:
929 {
930 /* allocate space for encoded string, including initial and final
931 quotes, a space for readability, and a final NULL */
932 encoded_string_length = 2 * string_length + 3;
933 tp = t = (char *)_pl_xmalloc ((encoded_string_length + 1) * sizeof(char));
934
935 /* begin with a space for readability, and a quote */
936 *tp++ = ' ';
937 *tp++ = (use_double_quotes ? '"' : '\'');
938 while ((c = *sp++) != '\0')
939 {
940 /* escape all quotes by doubling them */
941 if (((use_double_quotes == true) && c == '"')
942 || ((use_double_quotes == false) && c == '\''))
943 *tp++ = c;
944 *tp++ = c;
945 }
946 /* end with a quote */
947 *tp++ = (use_double_quotes ? '"' : '\'');
948 *tp++ = '\0';
949
950 strcpy (outbuf->point, t);
951 _update_buffer (outbuf);
952 free (t);
953 }
954 break;
955 }
956 }
957
958 /* Write the terminator of a CGM command. In the binary encoding this
959 writes a single null if and only if the number of bytes previously
960 written (kept track of via the `byte_count' pointer) is odd; otherwise
961 it does nothing. In the clear text encoding it writes ";\n". */
962
963 void
_cgm_emit_command_terminator(plOutbuf * outbuf,int cgm_encoding,int * byte_count)964 _cgm_emit_command_terminator (plOutbuf *outbuf, int cgm_encoding, int *byte_count)
965 {
966 switch (cgm_encoding)
967 {
968 case CGM_ENCODING_BINARY:
969 default:
970 if ((*byte_count) % 2 == 1)
971 {
972 *(outbuf->point) = '\0';
973 _update_buffer_by_added_bytes (outbuf, 1);
974 (*byte_count)++;
975 }
976 break;
977
978 case CGM_ENCODING_CHARACTER: /* not supported */
979 break;
980
981 case CGM_ENCODING_CLEAR_TEXT:
982 strcpy (outbuf->point, ";\n");
983 _update_buffer (outbuf);
984 break;
985 }
986 }
987