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