c_emit.c 32 KB

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