PLplot  5.11.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
plbuf.c
Go to the documentation of this file.
1 // Handle plot buffer.
2 //
3 // Copyright (C) 1992 Maurice LeBrun
4 // Copyright (C) 2004-2014 Alan W. Irwin
5 // Copyright (C) 2005 Thomas J. Duck
6 // Copyright (C) 2006 Jim Dishaw
7 //
8 // This file is part of PLplot.
9 //
10 // PLplot is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU Library General Public License as published
12 // by the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
14 //
15 // PLplot is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Library General Public License for more details.
19 //
20 // You should have received a copy of the GNU Library General Public License
21 // along with PLplot; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 //
24 
25 #define NEED_PLDEBUG
26 #include "plplotP.h"
27 #include "drivers.h"
28 #include "metadefs.h"
29 
30 #include <string.h>
31 
32 //
33 // Function prototypes
34 //
35 
36 // Public
37 void * plbuf_save( PLStream *pls, void *state );
38 
39 // Private
40 static void check_buffer_size( PLStream *pls, size_t data_size );
41 
42 static int rd_command( PLStream *pls, U_CHAR *p_c );
43 static void rd_data( PLStream *pls, void *buf, size_t buf_size );
44 static void rd_data_no_copy( PLStream *pls, void **buf, size_t buf_size );
45 
46 static void wr_command( PLStream *pls, U_CHAR c );
47 static void wr_data( PLStream *pls, void *buf, size_t buf_size );
48 
49 static void plbuf_control( PLStream *pls, U_CHAR c );
50 static void plbuf_fill( PLStream *pls );
51 static void plbuf_swin( PLStream *pls, PLWindow *plwin );
52 
53 static void rdbuf_init( PLStream *pls );
54 static void rdbuf_line( PLStream *pls );
55 static void rdbuf_polyline( PLStream *pls );
56 static void rdbuf_eop( PLStream *pls );
57 static void rdbuf_bop( PLStream *pls );
58 static void rdbuf_state( PLStream *pls );
59 static void rdbuf_esc( PLStream *pls );
60 static void rdbuf_image( PLStream *pls );
61 static void rdbuf_text( PLStream *pls );
62 static void rdbuf_text_unicode( PLINT op, PLStream *pls );
63 static void rdbuf_fill( PLStream *pls );
64 static void rdbuf_swin( PLStream *pls );
65 static void rdbuf_di( PLStream *pls );
66 
67 //--------------------------------------------------------------------------
68 // Plplot internal interface to the plot buffer
69 //--------------------------------------------------------------------------
70 
71 //--------------------------------------------------------------------------
72 // plbuf_init()
73 //
74 // Initialize device.
75 //--------------------------------------------------------------------------
76 
77 void
79 {
80  dbug_enter( "plbuf_init" );
81 
82  // Indicate that this buffer is not being read
83  pls->plbuf_read = FALSE;
84 
85  if ( pls->plbuf_buffer == NULL )
86  {
87  // We have not allocated a buffer, so do it now
88  pls->plbuf_buffer_grow = 128 * 1024;
89 
90  if ( ( pls->plbuf_buffer = malloc( pls->plbuf_buffer_grow ) ) == NULL )
91  plexit( "plbuf_init: Error allocating plot buffer." );
92 
94  pls->plbuf_top = 0;
95  pls->plbuf_readpos = 0;
96  }
97  else
98  {
99  // Buffer is allocated, move the top to the beginning
100  pls->plbuf_top = 0;
101  }
102 }
103 
104 //--------------------------------------------------------------------------
105 // plbuf_eop()
106 //
107 // End of page.
108 //--------------------------------------------------------------------------
109 
110 void
112 {
113  dbug_enter( "plbuf_eop" );
114 }
115 
116 //--------------------------------------------------------------------------
117 // plbuf_bop()
118 //
119 // Set up for the next page.
120 // To avoid problems redisplaying partially filled pages, on each BOP the
121 // old data in the buffer is ignored by setting the top back to the
122 // beginning of the buffer.
123 //
124 // Also write state information to ensure the next page is correct.
125 //--------------------------------------------------------------------------
126 
127 void
129 {
130  dbug_enter( "plbuf_bop" );
131 
132  plbuf_tidy( pls );
133 
134  // Move the top to the beginning
135  pls->plbuf_top = 0;
136 
137  wr_command( pls, (U_CHAR) BOP );
138 
139  // Save the current configuration (e.g. colormap, current colors) to
140  // allow plRemakePlot to correctly regenerate the plot
141 
142  // Save the current colors. Do not use the PLSTATE_* commands
143  // because the color might have already been set by the driver
144  // during initialization and this would result in an extraneous
145  // color command being sent. The goal is to preserve the current
146  // color state so that rdbuf_bop can restore it. This needs
147  // to occur immediately after the BOP command so that it can be
148  // read by rdbuf_bop.
149  wr_data( pls, &( pls->icol0 ), sizeof ( pls->icol0 ) );
150  wr_data( pls, &( pls->icol1 ), sizeof ( pls->icol1 ) );
151  wr_data( pls, &( pls->curcolor ), sizeof ( pls->curcolor ) );
152  wr_data( pls, &( pls->curcmap ), sizeof ( pls->curcmap ) );
153 
154  // Save all the other state parameters via the plbuf_state function
155  plbuf_state( pls, PLSTATE_CMAP0 );
156  plbuf_state( pls, PLSTATE_CMAP1 );
157  plbuf_state( pls, PLSTATE_WIDTH );
158  plbuf_state( pls, PLSTATE_FILL );
159  plbuf_state( pls, PLSTATE_CHR );
160  plbuf_state( pls, PLSTATE_SYM );
161 }
162 
163 //--------------------------------------------------------------------------
164 // plbuf_tidy()
165 //
166 // Close graphics file
167 //--------------------------------------------------------------------------
168 
169 void
171 {
172  dbug_enter( "plbuf_tidy" );
173 }
174 
175 //--------------------------------------------------------------------------
176 // plbuf_line()
177 //
178 // Draw a line in the current color from (x1,y1) to (x2,y2).
179 //--------------------------------------------------------------------------
180 
181 void
182 plbuf_line( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
183 {
184  short xpl[2], ypl[2];
185 
186  dbug_enter( "plbuf_line" );
187 
188  wr_command( pls, (U_CHAR) LINE );
189 
190  xpl[0] = x1a;
191  xpl[1] = x2a;
192  ypl[0] = y1a;
193  ypl[1] = y2a;
194 
195  wr_data( pls, xpl, sizeof ( short ) * 2 );
196  wr_data( pls, ypl, sizeof ( short ) * 2 );
197 }
198 
199 //--------------------------------------------------------------------------
200 // plbuf_polyline()
201 //
202 // Draw a polyline in the current color.
203 //--------------------------------------------------------------------------
204 
205 void
206 plbuf_polyline( PLStream *pls, short *xa, short *ya, PLINT npts )
207 {
208  dbug_enter( "plbuf_polyline" );
209 
210  wr_command( pls, (U_CHAR) POLYLINE );
211 
212  wr_data( pls, &npts, sizeof ( PLINT ) );
213 
214  wr_data( pls, xa, sizeof ( short ) * (size_t) npts );
215  wr_data( pls, ya, sizeof ( short ) * (size_t) npts );
216 }
217 
218 //--------------------------------------------------------------------------
219 // plbuf_state()
220 //
221 // Handle change in PLStream state (color, pen width, fill attribute, etc).
222 //--------------------------------------------------------------------------
223 
224 void
226 {
227  dbug_enter( "plbuf_state" );
228 
229  wr_command( pls, (U_CHAR) CHANGE_STATE );
230  wr_command( pls, (U_CHAR) op );
231 
232  switch ( op )
233  {
234  case PLSTATE_WIDTH:
235  wr_data( pls, &( pls->width ), sizeof ( pls->width ) );
236  break;
237 
238  case PLSTATE_COLOR0:
239  wr_data( pls, &( pls->icol0 ), sizeof ( pls->icol0 ) );
240  if ( pls->icol0 == PL_RGB_COLOR )
241  {
242  wr_data( pls, &( pls->curcolor.r ), sizeof ( pls->curcolor.r ) );
243  wr_data( pls, &( pls->curcolor.g ), sizeof ( pls->curcolor.g ) );
244  wr_data( pls, &( pls->curcolor.b ), sizeof ( pls->curcolor.b ) );
245  wr_data( pls, &( pls->curcolor.a ), sizeof ( pls->curcolor.a ) );
246  }
247  break;
248 
249  case PLSTATE_COLOR1:
250  wr_data( pls, &( pls->icol1 ), sizeof ( pls->icol1 ) );
251  break;
252 
253  case PLSTATE_FILL:
254  wr_data( pls, &( pls->patt ), sizeof ( pls->patt ) );
255  wr_data( pls, &( pls->nps ), sizeof ( pls->nps ) );
256  wr_data( pls, &( pls->inclin[0] ), sizeof ( pls->inclin ) );
257  wr_data( pls, &( pls->delta[0] ), sizeof ( pls->delta ) );
258  break;
259 
260  case PLSTATE_CMAP0:
261  // Save the number of colors in the palatte
262  wr_data( pls, &( pls->ncol0 ), sizeof ( pls->ncol0 ) );
263  // Save the color palatte
264  wr_data( pls, &( pls->cmap0[0] ), sizeof ( PLColor ) * pls->ncol0 );
265  break;
266 
267  case PLSTATE_CMAP1:
268  // Save the number of colors in the palatte
269  wr_data( pls, &( pls->ncol1 ), sizeof ( pls->ncol1 ) );
270  // Save the color palatte
271  wr_data( pls, &( pls->cmap1[0] ), sizeof ( PLColor ) * pls->ncol1 );
272  break;
273 
274  case PLSTATE_CHR:
275  //save the chrdef and chrht parameters
276  wr_data( pls, &( pls->chrdef ), sizeof ( pls->chrdef ) );
277  wr_data( pls, &( pls->chrht ), sizeof ( pls->chrht ) );
278  break;
279 
280  case PLSTATE_SYM:
281  //save the symdef and symht parameters
282  wr_data( pls, &( pls->symdef ), sizeof ( pls->symdef ) );
283  wr_data( pls, &( pls->symht ), sizeof ( pls->symht ) );
284  break;
285  }
286 }
287 
288 
289 //--------------------------------------------------------------------------
290 // plbuf_image()
291 //
292 // write image described in points pls->dev_x[], pls->dev_y[], pls->dev_z[].
293 // pls->nptsX, pls->nptsY.
294 //--------------------------------------------------------------------------
295 
296 static void
297 plbuf_image( PLStream *pls, IMG_DT *img_dt )
298 {
299  PLINT npts = pls->dev_nptsX * pls->dev_nptsY;
300 
301  dbug_enter( "plbuf_image" );
302 
303  wr_data( pls, &pls->dev_nptsX, sizeof ( PLINT ) );
304  wr_data( pls, &pls->dev_nptsY, sizeof ( PLINT ) );
305 
306  wr_data( pls, &img_dt->xmin, sizeof ( PLFLT ) );
307  wr_data( pls, &img_dt->ymin, sizeof ( PLFLT ) );
308  wr_data( pls, &img_dt->dx, sizeof ( PLFLT ) );
309  wr_data( pls, &img_dt->dy, sizeof ( PLFLT ) );
310 
311  wr_data( pls, &pls->dev_zmin, sizeof ( short ) );
312  wr_data( pls, &pls->dev_zmax, sizeof ( short ) );
313 
314  wr_data( pls, pls->dev_ix, sizeof ( short ) * (size_t) npts );
315  wr_data( pls, pls->dev_iy, sizeof ( short ) * (size_t) npts );
316  wr_data( pls, pls->dev_z,
317  sizeof ( unsigned short )
318  * (size_t) ( ( pls->dev_nptsX - 1 ) * ( pls->dev_nptsY - 1 ) ) );
319 }
320 
321 //--------------------------------------------------------------------------
322 // plbuf_text()
323 //
324 // Handle text call.
325 //--------------------------------------------------------------------------
326 
327 static void
329 {
330  dbug_enter( "plbuf_text" );
331 
332  // Check for missing data. The gcw driver needs this
333  if ( text == NULL )
334  return;
335 
336  // Store the state information needed to render the text
337 
338  wr_data( pls, &pls->chrht, sizeof ( pls->chrht ) );
339  wr_data( pls, &pls->diorot, sizeof ( pls->diorot ) );
340  wr_data( pls, &pls->clpxmi, sizeof ( pls->clpxmi ) );
341  wr_data( pls, &pls->clpxma, sizeof ( pls->clpxma ) );
342  wr_data( pls, &pls->clpymi, sizeof ( pls->clpymi ) );
343  wr_data( pls, &pls->clpyma, sizeof ( pls->clpyma ) );
344 
345  // Store the text layout information
346 
347  wr_data( pls, &text->base, sizeof ( text->base ) );
348  wr_data( pls, &text->just, sizeof ( text->just ) );
349  wr_data( pls, text->xform, sizeof ( text->xform[0] ) * 4 );
350  wr_data( pls, &text->x, sizeof ( text->x ) );
351  wr_data( pls, &text->y, sizeof ( text->y ) );
352  wr_data( pls, &text->refx, sizeof ( text->refx ) );
353  wr_data( pls, &text->refy, sizeof ( text->refy ) );
354  wr_data( pls, &text->font_face, sizeof ( text->font_face ) );
355 
356  // Store the text
357 
358  if ( pls->dev_unicode )
359  {
360  PLUNICODE fci;
361 
362  // Retrieve and store the font characterization integer
363  plgfci( &fci );
364 
365  wr_data( pls, &fci, sizeof ( fci ) );
366 
367  wr_data( pls, &text->unicode_array_len, sizeof ( U_SHORT ) );
368  if ( text->unicode_array_len )
369  wr_data( pls,
370  text->unicode_array,
371  sizeof ( PLUNICODE ) * text->unicode_array_len );
372  }
373  else
374  {
375  U_SHORT len;
376 
377  len = strlen( text->string );
378  wr_data( pls, &len, sizeof ( len ) );
379  if ( len > 0 )
380  wr_data( pls, (void *) text->string, sizeof ( char ) * len );
381  }
382 }
383 
384 //--------------------------------------------------------------------------
385 // plbuf_text_unicode()
386 //
387 // Handle text buffering for the new unicode pathway.
388 //--------------------------------------------------------------------------
389 
390 static void
392 {
393  PLUNICODE fci;
394 
395  dbug_enter( "plbuf_text_unicode" );
396 }
397 
398 
399 //--------------------------------------------------------------------------
400 // plbuf_esc()
401 //
402 // Escape function. Note that any data written must be in device
403 // independent form to maintain the transportability of the metafile.
404 //
405 // Functions:
406 //
407 // PLESC_FILL Fill polygon
408 // PLESC_SWIN Set plot window parameters
409 // PLESC_IMAGE Draw image
410 // PLESC_HAS_TEXT Draw PostScript text
411 // PLESC_CLEAR Clear Background
412 // PLESC_START_RASTERIZE
413 // PLESC_END_RASTERIZE Start and stop rasterization
414 //--------------------------------------------------------------------------
415 
416 void
417 plbuf_esc( PLStream *pls, PLINT op, void *ptr )
418 {
419  plbuffer *buffer;
420  dbug_enter( "plbuf_esc" );
421 
422  wr_command( pls, (U_CHAR) ESCAPE );
423  wr_command( pls, (U_CHAR) op );
424 
425  switch ( op )
426  {
427  case PLESC_FILL:
428  plbuf_fill( pls );
429  break;
430 
431  case PLESC_SWIN:
432  plbuf_swin( pls, (PLWindow *) ptr );
433  break;
434 
435  case PLESC_IMAGE:
436  plbuf_image( pls, (IMG_DT *) ptr );
437  break;
438 
439  // Unicode and non-Unicode text handling
440  case PLESC_HAS_TEXT:
441  plbuf_text( pls, (EscText *) ptr );
442  break;
443 
444  // Alternate Unicode text handling
445  case PLESC_BEGIN_TEXT:
446  case PLESC_TEXT_CHAR:
447  case PLESC_CONTROL_CHAR:
448  case PLESC_END_TEXT:
449  // The alternative unicode processing is not correctly implemented
450  // and is currently only used by Cairo, which handles its own
451  // redraws. Skip further processing for now
452 
453  //plbuf_text_unicode( pls, (EscText *) ptr );
454  break;
455 
456  case PLESC_IMPORT_BUFFER:
457  buffer = (plbuffer *) ptr;
458  if ( buffer->size > pls->plbuf_buffer_size )
459  {
460  pls->plbuf_buffer = realloc( pls->plbuf_buffer, buffer->size );
461  pls->plbuf_buffer_size = buffer->size;
462  }
463  if ( !pls->plbuf_buffer )
464  plexit( "plbuf_esc: Failed to reallocate buffer during PLESC_SET_BUFFER case" );
465  memcpy( pls->plbuf_buffer, buffer->buffer, buffer->size );
466  pls->plbuf_top = buffer->size;
467 
468 #if 0
469  // These are a no-op. They just need an entry in the buffer.
470  case PLESC_CLEAR:
472  case PLESC_END_RASTERIZE:
473  break;
474 #endif
475  }
476 }
477 
478 //--------------------------------------------------------------------------
479 // plbuf_di()
480 //
481 // Driver interface function. Saves all info needed for a call to pldi_ini()
482 // e.g.orientation etc.
483 //--------------------------------------------------------------------------
484 void plbuf_di( PLStream *pls )
485 {
487 
488  wr_data( pls, &pls->difilt, sizeof ( pls->difilt ) );
489  wr_data( pls, &pls->dipxmin, sizeof ( pls->dipxmin ) );
490  wr_data( pls, &pls->dipymin, sizeof ( pls->dipymin ) );
491  wr_data( pls, &pls->dipxmax, sizeof ( pls->dipxmax ) );
492  wr_data( pls, &pls->dipymax, sizeof ( pls->dipymax ) );
493  wr_data( pls, &pls->aspect, sizeof ( pls->aspect ) );
494  wr_data( pls, &pls->mar, sizeof ( pls->mar ) );
495  wr_data( pls, &pls->jx, sizeof ( pls->jx ) );
496  wr_data( pls, &pls->jy, sizeof ( pls->jy ) );
497  wr_data( pls, &pls->diorot, sizeof ( pls->diorot ) );
498  wr_data( pls, &pls->dimxmin, sizeof ( pls->dimxmin ) );
499  wr_data( pls, &pls->dimymin, sizeof ( pls->dimymin ) );
500  wr_data( pls, &pls->dimxmax, sizeof ( pls->dimxmax ) );
501  wr_data( pls, &pls->dimymax, sizeof ( pls->dimymax ) );
502  wr_data( pls, &pls->dimxpmm, sizeof ( pls->dimxpmm ) );
503  wr_data( pls, &pls->dimypmm, sizeof ( pls->dimypmm ) );
504 }
505 
506 //--------------------------------------------------------------------------
507 // plbuf_fill()
508 //
509 // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
510 //--------------------------------------------------------------------------
511 
512 static void
514 {
515  dbug_enter( "plbuf_fill" );
516 
517  wr_data( pls, &pls->dev_npts, sizeof ( PLINT ) );
518  wr_data( pls, pls->dev_x, sizeof ( short ) * (size_t) pls->dev_npts );
519  wr_data( pls, pls->dev_y, sizeof ( short ) * (size_t) pls->dev_npts );
520 }
521 
522 //--------------------------------------------------------------------------
523 // plbuf_swin()
524 //
525 // Set up plot window parameters.
526 //--------------------------------------------------------------------------
527 
528 static void
529 plbuf_swin( PLStream *pls, PLWindow *plwin )
530 {
531  dbug_enter( "plbuf_swin" );
532 
533  wr_data( pls, &plwin->dxmi, sizeof ( plwin->dxmi ) );
534  wr_data( pls, &plwin->dxma, sizeof ( plwin->dxma ) );
535  wr_data( pls, &plwin->dymi, sizeof ( plwin->dymi ) );
536  wr_data( pls, &plwin->dyma, sizeof ( plwin->dyma ) );
537 
538  wr_data( pls, &plwin->wxmi, sizeof ( plwin->wxmi ) );
539  wr_data( pls, &plwin->wxma, sizeof ( plwin->wxma ) );
540  wr_data( pls, &plwin->wymi, sizeof ( plwin->wymi ) );
541  wr_data( pls, &plwin->wyma, sizeof ( plwin->wyma ) );
542 }
543 
544 //--------------------------------------------------------------------------
545 // Routines to read from & process the plot buffer.
546 //--------------------------------------------------------------------------
547 
548 //--------------------------------------------------------------------------
549 // plbuf_write()
550 //
551 // Provides an interface for other parts of PLplot (e.g. plmetafile.c) to
552 // write into the buffer. The reason why wr_command and wr_data are not
553 // exposed is to help the optimizer to inline those two functions.
554 //--------------------------------------------------------------------------
555 void plbuf_write( PLStream *pls, void *data, size_t bytes )
556 {
557  wr_data( pls, data, bytes );
558 }
559 
560 //--------------------------------------------------------------------------
561 // rdbuf_init()
562 //
563 // Initialize device.
564 //--------------------------------------------------------------------------
565 
566 static void
568 {
569  dbug_enter( "rdbuf_init" );
570 }
571 
572 //--------------------------------------------------------------------------
573 // rdbuf_eop()
574 //
575 // End of page.
576 //--------------------------------------------------------------------------
577 
578 static void
580 {
581  dbug_enter( "rdbuf_eop" );
582 }
583 
584 //--------------------------------------------------------------------------
585 // rdbuf_bop()
586 //
587 // Set up for the next page.
588 //--------------------------------------------------------------------------
589 
590 static void
592 {
593  U_CHAR cmd;
594 
595  dbug_enter( "rdbuf_bop" );
596 
597  pls->nplwin = 0;
598 
599  // Read the current color state from the plot buffer
600  rd_data( pls, &( pls->icol0 ), sizeof ( pls->icol0 ) );
601  rd_data( pls, &( pls->icol1 ), sizeof ( pls->icol1 ) );
602  rd_data( pls, &( pls->curcolor ), sizeof ( pls->curcolor ) );
603  rd_data( pls, &( pls->curcmap ), sizeof ( pls->curcmap ) );
604 
605  // We need to read the colormaps that were stored by plbuf_bop
606  // now because when plP_state is used to set the color, a wrong
607  // colormap will be used if it was changed.
608  // Read the command (should be CHANGE_STATE PLSTATE_CMAP0)
609  rd_command( pls, &cmd );
610  plbuf_control( pls, cmd );
611  // Read the command (should be CHANGE_STATE PLSTATE_CMAP1)
612  rd_command( pls, &cmd );
613  plbuf_control( pls, cmd );
614  // Read the command (should be CHANGE_STATE PLSTATE_WIDTH)
615  rd_command( pls, &cmd );
616  plbuf_control( pls, cmd );
617  // Read the command (should be CHANGE_STATE PLSTATE_FILL)
618  rd_command( pls, &cmd );
619  plbuf_control( pls, cmd );
620  // Read the command (should be CHANGE_STATE PLSTATE_CHR)
621  rd_command( pls, &cmd );
622  plbuf_control( pls, cmd );
623  // Read the command (should be CHANGE_STATE PLSTATE_SYM)
624  rd_command( pls, &cmd );
625  plbuf_control( pls, cmd );
626 
627  // and now we can set the color
628  if ( pls->curcmap == 0 )
629  {
631  }
632  else
633  {
635  }
636 
637  plP_bop();
638 }
639 
640 //--------------------------------------------------------------------------
641 // rdbuf_line()
642 //
643 // Draw a line in the current color from (x1,y1) to (x2,y2).
644 //--------------------------------------------------------------------------
645 
646 static void
648 {
649  short *xpl, *ypl;
650  PLINT npts = 2;
651 
652  dbug_enter( "rdbuf_line" );
653 
654  // Use the "no copy" version because the endpoint data array does
655  // not need to persist outside of this function
656  rd_data_no_copy( pls, (void **) &xpl, sizeof ( short ) * (size_t) npts );
657  rd_data_no_copy( pls, (void **) &ypl, sizeof ( short ) * (size_t) npts );
658 
659  plP_line( xpl, ypl );
660 }
661 
662 //--------------------------------------------------------------------------
663 // rdbuf_polyline()
664 //
665 // Draw a polyline in the current color.
666 //--------------------------------------------------------------------------
667 
668 static void
670 {
671  short *xpl, *ypl;
672  PLINT npts;
673 
674  dbug_enter( "rdbuf_polyline" );
675 
676  rd_data( pls, &npts, sizeof ( PLINT ) );
677 
678  // Use the "no copy" version because the node data array does
679  // not need to persist outside of ths function
680  rd_data_no_copy( pls, (void **) &xpl, sizeof ( short ) * (size_t) npts );
681  rd_data_no_copy( pls, (void **) &ypl, sizeof ( short ) * (size_t) npts );
682 
683  plP_polyline( xpl, ypl, npts );
684 }
685 
686 //--------------------------------------------------------------------------
687 // rdbuf_state()
688 //
689 // Handle change in PLStream state (color, pen width, fill attribute, etc).
690 //--------------------------------------------------------------------------
691 
692 static void
694 {
695  U_CHAR op;
696 
697  dbug_enter( "rdbuf_state" );
698 
699  rd_data( pls, &op, sizeof ( U_CHAR ) );
700 
701  switch ( op )
702  {
703  case PLSTATE_WIDTH: {
704  rd_data( pls, &( pls->width ), sizeof ( pls->width ) );
706 
707  break;
708  }
709 
710  case PLSTATE_COLOR0: {
711  U_CHAR r, g, b;
712  PLFLT a;
713 
714  rd_data( pls, &( pls->icol0 ), sizeof ( pls->icol0 ) );
715  if ( pls->icol0 == PL_RGB_COLOR )
716  {
717  rd_data( pls, &r, sizeof ( U_CHAR ) );
718  rd_data( pls, &g, sizeof ( U_CHAR ) );
719  rd_data( pls, &b, sizeof ( U_CHAR ) );
720  rd_data( pls, &a, sizeof ( U_CHAR ) );
721  }
722  else
723  {
724  if ( pls->icol0 >= pls->ncol0 )
725  {
726  char buffer[256];
727  snprintf( buffer, 256,
728  "rdbuf_state: Invalid color map entry: %d",
729  pls->icol0 );
730  plabort( buffer );
731  return;
732  }
733  r = pls->cmap0[pls->icol0].r;
734  g = pls->cmap0[pls->icol0].g;
735  b = pls->cmap0[pls->icol0].b;
736  a = pls->cmap0[pls->icol0].a;
737  }
738  pls->curcolor.r = r;
739  pls->curcolor.g = g;
740  pls->curcolor.b = b;
741  pls->curcolor.a = a;
742  pls->curcmap = 0;
743 
745  break;
746  }
747 
748  case PLSTATE_COLOR1: {
749  rd_data( pls, &( pls->icol1 ), sizeof ( pls->icol1 ) );
750 
751  pls->curcolor.r = pls->cmap1[pls->icol1].r;
752  pls->curcolor.g = pls->cmap1[pls->icol1].g;
753  pls->curcolor.b = pls->cmap1[pls->icol1].b;
754  pls->curcolor.a = pls->cmap1[pls->icol1].a;
755  pls->curcmap = 1;
756 
758  break;
759  }
760 
761  case PLSTATE_FILL: {
762  PLINT patt, nps, inclin[2], delta[2];
763  rd_data( pls, &patt, sizeof ( patt ) );
764  rd_data( pls, &nps, sizeof ( nps ) );
765  rd_data( pls, &inclin[0], sizeof ( inclin ) );
766  rd_data( pls, &delta[0], sizeof ( delta ) );
767  if ( nps != 0 )
768  c_plpat( nps, inclin, delta );
769  pls->patt = patt; //this must be second as c_plpat sets pls->patt to an nvalid value
770  break;
771  }
772 
773  case PLSTATE_CMAP0: {
774  PLINT ncol;
775  size_t size;
776 
777  rd_data( pls, &ncol, sizeof ( ncol ) );
778 
779  // Calculate the memory size for this color palatte
780  size = (size_t) ncol * sizeof ( PLColor );
781 
782  if ( pls->ncol0 == 0 || pls->ncol0 != ncol )
783  {
784  // The current palatte is empty or the current palatte is not
785  // correctly sized, thus we need allocate a new one
786 
787  // If we have a colormap, discard it because we do not use
788  // realloc(). We are going to read the colormap from the buffer
789  if ( pls->cmap0 != NULL )
790  free( pls->cmap0 );
791 
792  if ( ( pls->cmap0 = (PLColor *) malloc( size ) ) == NULL )
793  {
794  plexit( "Insufficient memory for colormap 0" );
795  }
796  }
797 
798  // Now read the colormap from the buffer
799  rd_data( pls, &( pls->cmap0[0] ), size );
800  pls->ncol0 = ncol;
801 
803  break;
804  }
805 
806  case PLSTATE_CMAP1: {
807  PLINT ncol;
808  size_t size;
809 
810  rd_data( pls, &ncol, sizeof ( ncol ) );
811 
812  // Calculate the memory size for this color palatte
813  size = (size_t) ncol * sizeof ( PLColor );
814 
815  if ( pls->ncol1 == 0 || pls->ncol1 != ncol )
816  {
817  // The current palatte is empty or the current palatte is not
818  // correctly sized, thus we need allocate a new one
819 
820  // If we have a colormap, discard it because we do not use
821  // realloc(). We are going to read the colormap from the buffer
822  if ( pls->cmap1 != NULL )
823  free( pls->cmap1 );
824 
825  if ( ( pls->cmap1 = (PLColor *) malloc( size ) ) == NULL )
826  {
827  plexit( "Insufficient memory for colormap 1" );
828  }
829  }
830 
831  // Now read the colormap from the buffer
832  rd_data( pls, &( pls->cmap1[0] ), size );
833  pls->ncol1 = ncol;
834 
836  break;
837  }
838 
839  case PLSTATE_CHR: {
840  //read the chrdef and chrht parameters
841  rd_data( pls, &( pls->chrdef ), sizeof ( pls->chrdef ) );
842  rd_data( pls, &( pls->chrht ), sizeof ( pls->chrht ) );
843  break;
844  }
845 
846  case PLSTATE_SYM: {
847  //read the symdef and symht parameters
848  rd_data( pls, &( pls->symdef ), sizeof ( pls->symdef ) );
849  rd_data( pls, &( pls->symht ), sizeof ( pls->symht ) );
850  break;
851  }
852  }
853 }
854 
855 //--------------------------------------------------------------------------
856 // rdbuf_esc()
857 //
858 // Escape function.
859 // Must fill data structure with whatever data that was written,
860 // then call escape function.
861 //
862 // Note: it is best to only call the escape function for op-codes that
863 // are known to be supported.
864 //
865 // Functions:
866 //
867 // PLESC_FILL Fill polygon
868 // PLESC_SWIN Set plot window parameters
869 // PLESC_IMAGE Draw image
870 // PLESC_HAS_TEXT Draw PostScript text
871 // PLESC_BEGIN_TEXT Commands for the alternative unicode text
872 // PLESC_TEXT_CHAR handling path
873 // PLESC_CONTROL_CHAR
874 // PLESC_END_TEXT
875 // PLESC_CLEAR Clear Background
876 //--------------------------------------------------------------------------
877 
878 static void
880 {
881  U_CHAR op;
882 
883  dbug_enter( "rdbuf_esc" );
884 
885  rd_data( pls, &op, sizeof ( U_CHAR ) );
886 
887  switch ( op )
888  {
889  case PLESC_FILL:
890  rdbuf_fill( pls );
891  break;
892  case PLESC_SWIN:
893  rdbuf_swin( pls );
894  break;
895  case PLESC_IMAGE:
896  rdbuf_image( pls );
897  break;
898  case PLESC_HAS_TEXT:
899  rdbuf_text( pls );
900  break;
901  case PLESC_BEGIN_TEXT:
902  case PLESC_TEXT_CHAR:
903  case PLESC_CONTROL_CHAR:
904  case PLESC_END_TEXT:
905  // Disable for now because alternative unicode processing is
906  // not correctly implemented
907 
908  //rdbuf_text_unicode( op, pls );
909  break;
910  case PLESC_IMPORT_BUFFER:
911  // Place holder until an appropriate action is determined.
912  // Should this even be an ESC operation?
913  break;
914  case PLESC_CLEAR:
915  plP_esc( PLESC_CLEAR, NULL );
916  break;
919  break;
920  case PLESC_END_RASTERIZE:
921  plP_esc( PLESC_END_RASTERIZE, NULL );
922  break;
923  }
924 }
925 
926 //--------------------------------------------------------------------------
927 // rdbuf_fill()
928 //
929 // Fill polygon described by input points.
930 //--------------------------------------------------------------------------
931 
932 static void
934 {
935  short *xpl, *ypl;
936  PLINT npts;
937 
938  dbug_enter( "rdbuf_fill" );
939 
940  rd_data( pls, &npts, sizeof ( PLINT ) );
941 
942  rd_data_no_copy( pls, (void **) &xpl, sizeof ( short ) * (size_t) npts );
943  rd_data_no_copy( pls, (void **) &ypl, sizeof ( short ) * (size_t) npts );
944 
945  plP_fill( xpl, ypl, npts );
946 }
947 
948 //--------------------------------------------------------------------------
949 // rdbuf_image()
950 //
951 // .
952 //--------------------------------------------------------------------------
953 
954 static void
956 {
957  // Unnecessarily initialize dev_iy and dev_z to quiet -O1
958  // -Wuninitialized warnings which are false alarms. (If something
959  // goes wrong with the dev_ix malloc below any further use of
960  // dev_iy and dev_z does not occur. Similarly, if something goes
961  // wrong with the dev_iy malloc below any further use of dev_z
962  // does not occur.)
963  short *dev_ix, *dev_iy = NULL;
964  unsigned short *dev_z = NULL, dev_zmin, dev_zmax;
965  PLINT nptsX, nptsY, npts;
966  PLFLT xmin, ymin, dx, dy;
967 
968  dbug_enter( "rdbuf_image" );
969 
970  rd_data( pls, &nptsX, sizeof ( PLINT ) );
971  rd_data( pls, &nptsY, sizeof ( PLINT ) );
972  npts = nptsX * nptsY;
973 
974  rd_data( pls, &xmin, sizeof ( PLFLT ) );
975  rd_data( pls, &ymin, sizeof ( PLFLT ) );
976  rd_data( pls, &dx, sizeof ( PLFLT ) );
977  rd_data( pls, &dy, sizeof ( PLFLT ) );
978 
979  rd_data( pls, &dev_zmin, sizeof ( short ) );
980  rd_data( pls, &dev_zmax, sizeof ( short ) );
981 
982  // NOTE: Even though for memory buffered version all the data is in memory,
983  // we still allocate and copy the data because I think that method works
984  // better in a multithreaded environment. I could be wrong.
985  //
986  if ( ( ( dev_ix = (short *) malloc( (size_t) npts * sizeof ( short ) ) ) == NULL ) ||
987  ( ( dev_iy = (short *) malloc( (size_t) npts * sizeof ( short ) ) ) == NULL ) ||
988  ( ( dev_z = (unsigned short *) malloc( (size_t) ( ( nptsX - 1 ) * ( nptsY - 1 ) ) * sizeof ( unsigned short ) ) ) == NULL ) )
989  plexit( "rdbuf_image: Insufficient memory" );
990 
991  rd_data( pls, dev_ix, sizeof ( short ) * (size_t) npts );
992  rd_data( pls, dev_iy, sizeof ( short ) * (size_t) npts );
993  rd_data( pls, dev_z,
994  sizeof ( unsigned short )
995  * (size_t) ( ( nptsX - 1 ) * ( nptsY - 1 ) ) );
996 
997  //
998  // COMMENTED OUT by Hezekiah Carty
999  // Commented (hopefullly temporarily) until the dev_fastimg rendering
1000  // path can be updated to support the new plimage internals. In the
1001  // meantime this function is not actually used so the issue of how to
1002  // update the code to support the new interface can be ignored.
1003  //
1004  //plP_image(dev_ix, dev_iy, dev_z, nptsX, nptsY, xmin, ymin, dx, dy, dev_zmin, dev_zmax);
1005 
1006  free( dev_ix );
1007  free( dev_iy );
1008  free( dev_z );
1009 }
1010 
1011 //--------------------------------------------------------------------------
1012 // rdbuf_swin()
1013 //
1014 // Set up plot window parameters.
1015 //--------------------------------------------------------------------------
1016 
1017 static void
1019 {
1020  PLWindow plwin;
1021 
1022  dbug_enter( "rdbuf_swin" );
1023 
1024  rd_data( pls, &plwin.dxmi, sizeof ( plwin.dxmi ) );
1025  rd_data( pls, &plwin.dxma, sizeof ( plwin.dxma ) );
1026  rd_data( pls, &plwin.dymi, sizeof ( plwin.dymi ) );
1027  rd_data( pls, &plwin.dyma, sizeof ( plwin.dyma ) );
1028 
1029  rd_data( pls, &plwin.wxmi, sizeof ( plwin.wxmi ) );
1030  rd_data( pls, &plwin.wxma, sizeof ( plwin.wxma ) );
1031  rd_data( pls, &plwin.wymi, sizeof ( plwin.wymi ) );
1032  rd_data( pls, &plwin.wyma, sizeof ( plwin.wyma ) );
1033 
1034  plP_swin( &plwin );
1035 }
1036 
1037 
1038 //--------------------------------------------------------------------------
1039 // rdbuf_swin()
1040 //
1041 // Set up driver interface data
1042 //--------------------------------------------------------------------------
1043 static void
1045 {
1046  PLINT difilt;
1047  PLFLT rot;
1048  PLFLT dimxmin, dimxmax, dimymin, dimymax, dimxpmm, dimypmm;
1049  PLFLT dipxmin, dipymin, dipxmax, dipymax;
1050  PLFLT aspect, mar, jx, jy;
1051  rd_data( pls, &difilt, sizeof ( difilt ) );
1052  rd_data( pls, &dipxmin, sizeof ( dipxmin ) );
1053  rd_data( pls, &dipymin, sizeof ( dipymin ) );
1054  rd_data( pls, &dipxmax, sizeof ( dipxmax ) );
1055  rd_data( pls, &dipymax, sizeof ( dipymax ) );
1056  rd_data( pls, &aspect, sizeof ( aspect ) );
1057  rd_data( pls, &mar, sizeof ( mar ) );
1058  rd_data( pls, &jx, sizeof ( jx ) );
1059  rd_data( pls, &jy, sizeof ( jy ) );
1060  rd_data( pls, &rot, sizeof ( rot ) );
1061  rd_data( pls, &dimxmin, sizeof ( dimxmin ) );
1062  rd_data( pls, &dimymin, sizeof ( dimymin ) );
1063  rd_data( pls, &dimxmax, sizeof ( dimxmax ) );
1064  rd_data( pls, &dimymax, sizeof ( dimymax ) );
1065  rd_data( pls, &dimxpmm, sizeof ( dimxpmm ) );
1066  rd_data( pls, &dimypmm, sizeof ( dimypmm ) );
1067  if ( difilt & PLDI_MAP )
1068  c_plsdimap( dimxmin, dimxmax, dimymin, dimymax, dimxpmm, dimypmm );
1069  if ( difilt & PLDI_ORI )
1070  c_plsdiori( rot );
1071  if ( difilt & PLDI_PLT )
1072  c_plsdiplt( dipxmin, dipymin, dipxmax, dipymax );
1073  if ( difilt & PLDI_DEV )
1074  c_plsdidev( mar, aspect, jx, jy );
1075 }
1076 
1077 //--------------------------------------------------------------------------
1078 // rdbuf_text()
1079 //
1080 // Render text through the driver.
1081 //--------------------------------------------------------------------------
1082 
1083 static void
1085 {
1086  EscText text;
1087  PLFLT xform[4];
1088 
1089  dbug_enter( "rdbuf_text" );
1090 
1091  text.xform = xform;
1092 
1093  // Read the state information
1094 
1095  rd_data( pls, &pls->chrht, sizeof ( pls->chrht ) );
1096  rd_data( pls, &pls->diorot, sizeof ( pls->diorot ) );
1097  rd_data( pls, &pls->clpxmi, sizeof ( pls->clpxmi ) );
1098  rd_data( pls, &pls->clpxma, sizeof ( pls->clpxma ) );
1099  rd_data( pls, &pls->clpymi, sizeof ( pls->clpymi ) );
1100  rd_data( pls, &pls->clpyma, sizeof ( pls->clpyma ) );
1101 
1102  // Read the text layout information
1103 
1104  rd_data( pls, &text.base, sizeof ( text.base ) );
1105  rd_data( pls, &text.just, sizeof ( text.just ) );
1106  rd_data( pls, text.xform, sizeof ( text.xform[0] ) * 4 );
1107  rd_data( pls, &text.x, sizeof ( text.x ) );
1108  rd_data( pls, &text.y, sizeof ( text.y ) );
1109  rd_data( pls, &text.refx, sizeof ( text.refx ) );
1110  rd_data( pls, &text.refy, sizeof ( text.refy ) );
1111  rd_data( pls, &text.font_face, sizeof ( text.font_face ) );
1112 
1113  // Read in the text
1114  if ( pls->dev_unicode )
1115  {
1116  PLUNICODE fci;
1117 
1118  rd_data( pls, &fci, sizeof ( fci ) );
1119  plsfci( fci );
1120 
1121  rd_data( pls, &text.unicode_array_len, sizeof ( U_SHORT ) );
1122  if ( text.unicode_array_len )
1123  {
1124  // Set the pointer to the unicode data in the buffer. This avoids
1125  // allocating and freeing memory
1127  pls,
1128  (void **) ( &text.unicode_array ),
1129  sizeof ( PLUNICODE ) * text.unicode_array_len );
1130  }
1131  else
1132  {
1133  text.unicode_array = NULL;
1134  }
1135  }
1136  else
1137  {
1138  U_SHORT len;
1139 
1140  rd_data( pls, &len, sizeof ( len ) );
1141  if ( len > 0 )
1142  {
1143  // Set the pointer to the string data in the buffer. This avoids
1144  // allocating and freeing memory
1146  pls,
1147  (void **) ( &text.string ),
1148  sizeof ( char ) * len );
1149  }
1150  else
1151  {
1152  text.string = NULL;
1153  }
1154  }
1155 
1156  plP_esc( PLESC_HAS_TEXT, &text );
1157 }
1158 
1159 //--------------------------------------------------------------------------
1160 // rdbuf_text_unicode()
1161 //
1162 // Draw text for the new unicode handling pathway.
1163 // This currently does nothing but is here as a placehlder for the future
1164 //--------------------------------------------------------------------------
1165 
1166 static void
1168 {
1169  dbug_enter( "rdbuf_text_unicode" );
1170 }
1171 
1172 //--------------------------------------------------------------------------
1173 // plRemakePlot()
1174 //
1175 // Rebuilds plot from plot buffer, usually in response to a window
1176 // resize or exposure event.
1177 //--------------------------------------------------------------------------
1178 
1179 void
1181 {
1182  U_CHAR c;
1184  PLINT cursub;
1185 
1186  dbug_enter( "plRemakePlot" );
1187 
1188  // Change the status of the flags before checking for a buffer.
1189  // Actually, more thought is needed if we want to support multithreaded
1190  // code correctly, specifically the case where two threads are using
1191  // the same plot stream (e.g. one thread is drawing the plot and another
1192  // thread is processing window manager messages).
1193  //
1194  plbuf_write = pls->plbuf_write;
1195  cursub = pls->cursub;
1196  pls->plbuf_write = FALSE;
1197  pls->plbuf_read = TRUE;
1198 
1199  if ( pls->plbuf_buffer )
1200  {
1201  // State saving variables
1202  PLStream *save_current_pls;
1203 
1204  pls->plbuf_readpos = 0;
1205 
1206  // Save state
1207 
1208  // Need to change where plsc (current plot stream) points to before
1209  // processing the commands. If we have multiple plot streams, this
1210  // will prevent the commands from going to the wrong plot stream.
1211  //
1212  save_current_pls = plsc;
1213 
1214  // Make the current plot stream the one passed by the caller
1215  plsc = pls;
1216 
1217  //end any current page on the destination stream.
1218  //This will do nothing if we are already at the end
1219  //of a page.
1220  //Doing this ensures that the first bop command in the
1221  //buffer actually does something
1222  plP_eop();
1223 
1224  // Restore the
1225  // Replay the plot command buffer
1226  while ( rd_command( pls, &c ) )
1227  {
1228  plbuf_control( pls, c );
1229  }
1230 
1231  // Restore the original current plot stream
1232  plsc = save_current_pls;
1233  }
1234 
1235  // Restore the state of the passed plot stream
1236  pls->plbuf_read = FALSE;
1237  pls->plbuf_write = plbuf_write;
1238  pls->cursub = cursub;
1239 }
1240 
1241 //--------------------------------------------------------------------------
1242 // plbuf_control()
1243 //
1244 // Processes commands read from the plot buffer.
1245 //--------------------------------------------------------------------------
1246 
1247 static void
1249 {
1250  static U_CHAR c_old = 0;
1251 
1252  dbug_enter( "plbuf_control" );
1253 
1254  //#define CLOSE 2
1255  //#define LINETO 10
1256  //#define END_OF_FIELD 255
1257 
1258  switch ( (int) c )
1259  {
1260  case INITIALIZE:
1261  rdbuf_init( pls );
1262  break;
1263 
1264  case EOP:
1265  rdbuf_eop( pls );
1266  break;
1267 
1268  case BOP0:
1269  case BOP:
1270  rdbuf_bop( pls );
1271  break;
1272 
1273  case CHANGE_STATE:
1274  rdbuf_state( pls );
1275  break;
1276 
1277  case LINE:
1278  rdbuf_line( pls );
1279  break;
1280 
1281  case POLYLINE:
1282  rdbuf_polyline( pls );
1283  break;
1284 
1285  case ESCAPE:
1286  rdbuf_esc( pls );
1287  break;
1288 
1289  case DRIVER_INTERFACE:
1290  rdbuf_di( pls );
1291  break;
1292 
1293  // Obsolete commands, left here to maintain compatibility with previous
1294  // version of plot metafiles
1295  case SWITCH_TO_TEXT: // Obsolete, replaced by ESCAPE
1296  case SWITCH_TO_GRAPH: // Obsolete, replaced by ESCAPE
1297  case NEW_COLOR: // Obsolete, replaced by CHANGE_STATE
1298  case NEW_COLOR1:
1299  case NEW_WIDTH: // Obsolete, replaced by CHANGE_STATE
1300  case ADVANCE: // Obsolete, BOP/EOP used instead
1301  pldebug( "plbuf_control", "Obsolete command %d, ignoring\n", c );
1302  break;
1303 
1304  default:
1305  pldebug( "plbuf_control", "Unrecognized command %d, previous %d\n",
1306  c, c_old );
1307  plexit( "Unrecognized command" );
1308  }
1309  c_old = c;
1310 }
1311 
1312 //--------------------------------------------------------------------------
1313 // rd_command()
1314 //
1315 // Read & return the next command
1316 //--------------------------------------------------------------------------
1317 
1318 static int
1320 {
1321  int count;
1322 
1323  if ( pls->plbuf_readpos < pls->plbuf_top )
1324  {
1325  *p_c = *(U_CHAR *) ( (uint8_t *) pls->plbuf_buffer + pls->plbuf_readpos );
1326 
1327  // Advance the buffer position to maintain two-byte alignment
1328  pls->plbuf_readpos += sizeof ( uint16_t );
1329 
1330  count = sizeof ( U_CHAR );
1331  }
1332  else
1333  {
1334  count = 0;
1335  }
1336 
1337  return ( count );
1338 }
1339 
1340 //--------------------------------------------------------------------------
1341 // rd_data()
1342 //
1343 // Read the data associated with the command
1344 //--------------------------------------------------------------------------
1345 
1346 static void
1347 rd_data( PLStream *pls, void *buf, size_t buf_size )
1348 {
1349  memcpy( buf, (uint8_t *) pls->plbuf_buffer + pls->plbuf_readpos, buf_size );
1350 
1351  // Advance position but maintain alignment
1352  pls->plbuf_readpos += ( buf_size + ( buf_size % sizeof ( uint16_t ) ) );
1353 }
1354 
1355 //--------------------------------------------------------------------------
1356 // rd_data_no_copy()
1357 //
1358 // Read the data associated with the command by setting a pointer to the
1359 // position in the plot buffer. This avoids having to allocate space
1360 // and doing a memcpy. Useful for commands that do not need the data
1361 // to persist (like LINE and POLYLINE). Do not use for commands that
1362 // has data that needs to persist or are freed elsewhere (like COLORMAPS).
1363 //--------------------------------------------------------------------------
1364 
1365 static void
1366 rd_data_no_copy( PLStream *pls, void **buf, size_t buf_size )
1367 {
1368  ( *buf ) = (uint8_t *) pls->plbuf_buffer + pls->plbuf_readpos;
1369 
1370  // Advance position but maintain alignment
1371  pls->plbuf_readpos += ( buf_size + ( buf_size % sizeof ( uint16_t ) ) );
1372 }
1373 
1374 //--------------------------------------------------------------------------
1375 // check_buffer_size()
1376 //
1377 // Checks that the buffer has space to store the desired amount of data.
1378 // If not, the buffer is resized to accomodate the request
1379 //--------------------------------------------------------------------------
1380 static void
1381 check_buffer_size( PLStream *pls, size_t data_size )
1382 {
1383  size_t required_size;
1384 
1385  required_size = pls->plbuf_top + data_size;
1386 
1387  if ( required_size >= pls->plbuf_buffer_size )
1388  {
1389  if ( pls->plbuf_buffer_grow == 0 )
1390  pls->plbuf_buffer_grow = 128 * 1024;
1391 
1392  // Not enough space, need to grow the buffer before memcpy
1393  // Must make sure the increase is enough for this data, so
1394  // Determine the amount of space required and grow in multiples
1395  // of plbuf_buffer_grow
1396  pls->plbuf_buffer_size += pls->plbuf_buffer_grow *
1397  ( ( required_size
1398  - pls->plbuf_buffer_size )
1399  / pls->plbuf_buffer_grow
1400  + 1 );
1401 
1402  if ( pls->verbose )
1403  printf( "Growing buffer to %d KB\n",
1404  (int) ( pls->plbuf_buffer_size / 1024 ) );
1405 
1406  if ( ( pls->plbuf_buffer
1407  = realloc( pls->plbuf_buffer, pls->plbuf_buffer_size )
1408  ) == NULL )
1409  plexit( "plbuf buffer grow: Plot buffer grow failed" );
1410  }
1411 }
1412 
1413 //--------------------------------------------------------------------------
1414 // wr_command()
1415 //
1416 // Write the next command
1417 //--------------------------------------------------------------------------
1418 
1419 static void
1421 {
1422  check_buffer_size( pls, sizeof ( U_CHAR ) );
1423 
1424  *(U_CHAR *) ( (uint8_t *) pls->plbuf_buffer + pls->plbuf_top ) = c;
1425 
1426  // Advance buffer position to maintain two-byte alignment. This
1427  // will waste a little bit of space, but it prevents memory
1428  // alignment problems
1429  pls->plbuf_top += sizeof ( uint16_t );
1430 }
1431 
1432 //--------------------------------------------------------------------------
1433 // wr_data()
1434 //
1435 // Write the data associated with a command
1436 //--------------------------------------------------------------------------
1437 
1438 static void
1439 wr_data( PLStream *pls, void *buf, size_t buf_size )
1440 {
1441  check_buffer_size( pls, buf_size );
1442  memcpy( (uint8_t *) pls->plbuf_buffer + pls->plbuf_top, buf, buf_size );
1443 
1444  // Advance position but maintain alignment
1445  pls->plbuf_top += ( buf_size + ( buf_size % sizeof ( uint16_t ) ) );
1446 }
1447 
1448 
1449 //--------------------------------------------------------------------------
1450 // Plot buffer state saving
1451 //--------------------------------------------------------------------------
1452 
1453 // plbuf_save(state)
1454 //
1455 // Saves the current state of the plot into a save buffer.
1456 // This code was originally in gcw.c and gcw-lib.c. The original
1457 // code used a temporary file for the plot buffer and memory
1458 // to perserve colormaps. That method does not offer a clean
1459 // break between using memory buffers and file buffers. This
1460 // function preserves the same functionality by returning a data
1461 // structure that saves the plot buffer.
1462 //
1463 // The caller passes an existing save buffer for reuse or NULL
1464 // to force the allocation of a new buffer. Since one malloc()
1465 // is used for everything, the entire save buffer can be freed
1466 // with one free() call.
1467 //
1468 //
1469 struct _state
1470 {
1471  size_t size; // Size of the save buffer
1472  int valid; // Flag to indicate a valid save state
1475  size_t plbuf_top;
1477 };
1478 
1479 void * plbuf_save( PLStream *pls, void *state )
1480 {
1481  size_t save_size;
1482  struct _state *plot_state = (struct _state *) state;
1483  PLINT i;
1484  U_CHAR *buf; // Assume that this is byte-sized
1485 
1486  dbug_enter( "plbuf_save" );
1487 
1488  // If the plot buffer is not being used, there is no state to save
1489  if ( !pls->plbuf_write )
1490  return NULL;
1491 
1492  pls->plbuf_write = FALSE;
1493  pls->plbuf_read = TRUE;
1494 
1495  // Determine the size of the buffer required to save everything.
1496  save_size = sizeof ( struct _state );
1497 
1498  // Only copy as much of the plot buffer that is being used
1499  save_size += pls->plbuf_top;
1500 
1501  // If a buffer exists, determine if we need to resize it
1502  if ( state != NULL )
1503  {
1504  // We have a save buffer, is it smaller than the current size
1505  // requirement?
1506  if ( plot_state->size < save_size )
1507  {
1508  // Yes, reallocate a larger one
1509  if ( ( plot_state = (struct _state *) realloc( state, save_size ) ) == NULL )
1510  {
1511  // NOTE: If realloc fails, then plot_state will be NULL.
1512  // This will leave the original buffer untouched, thus we
1513  // mark it as invalid and return it back to the caller.
1514  //
1515  plwarn( "plbuf: Unable to reallocate sufficient memory to save state" );
1516  plot_state->valid = 0;
1517 
1518  return state;
1519  }
1520  plot_state->size = save_size;
1521  }
1522  }
1523  else
1524  {
1525  // A buffer does not exist, so we need to allocate one
1526  if ( ( plot_state = (struct _state *) malloc( save_size ) ) == NULL )
1527  {
1528  plwarn( "plbuf: Unable to allocate sufficient memory to save state" );
1529 
1530  return NULL;
1531  }
1532  plot_state->size = save_size;
1533  }
1534 
1535  // At this point we have an appropriately sized save buffer.
1536  // We need to invalidate the state of the save buffer, since it
1537  // will not be valid until after everything is copied. We use
1538  // this approach vice freeing the memory and returning a NULL pointer
1539  // in order to prevent allocating and freeing memory needlessly.
1540  //
1541  plot_state->valid = 0;
1542 
1543  // Point buf to the space after the struct _state
1544  buf = (U_CHAR *) ( plot_state + 1 );
1545 
1546  // Again, note, that we only copy the portion of the plot buffer that
1547  // is being used
1548  plot_state->plbuf_buffer_size = pls->plbuf_top;
1549  plot_state->plbuf_top = pls->plbuf_top;
1550  plot_state->plbuf_readpos = 0;
1551 
1552  // Create a pointer that points in the space we allocated after
1553  // struct _state
1554  plot_state->plbuf_buffer = (void *) buf;
1555  buf += pls->plbuf_top;
1556 
1557  // Copy the plot buffer to our new buffer. Again, I must stress, that
1558  // we only are copying the portion of the plot buffer that is being used
1559  //
1560  if ( memcpy( plot_state->plbuf_buffer, pls->plbuf_buffer, pls->plbuf_top ) == NULL )
1561  {
1562  // This should never be NULL
1563  plwarn( "plbuf: Got a NULL in memcpy!" );
1564  return (void *) plot_state;
1565  }
1566 
1567  pls->plbuf_write = TRUE;
1568  pls->plbuf_read = FALSE;
1569 
1570  plot_state->valid = 1;
1571  return (void *) plot_state;
1572 }
1573 
1574 // plbuf_restore(PLStream *, state)
1575 //
1576 // Restores the passed state
1577 //
1578 void plbuf_restore( PLStream *pls, void *state )
1579 {
1580  struct _state *new_state = (struct _state *) state;
1581 
1582  dbug_enter( "plbuf_restore" );
1583 
1584  pls->plbuf_buffer = new_state->plbuf_buffer;
1585  pls->plbuf_buffer_size = new_state->plbuf_buffer_size;
1586  pls->plbuf_top = new_state->plbuf_top;
1587  pls->plbuf_readpos = new_state->plbuf_readpos;
1588 }
1589 
1590 // plbuf_switch(PLStream *, state)
1591 //
1592 // Makes the passed state the current one. Preserves the previous state
1593 // by returning a save buffer.
1594 //
1595 // NOTE: The current implementation can cause a memory leak under the
1596 // following scenario:
1597 // 1) plbuf_save() is called
1598 // 2) plbuf_switch() is called
1599 // 3) Commands are called which cause the plot buffer to grow
1600 // 4) plbuf_swtich() is called
1601 //
1602 void * plbuf_switch( PLStream *pls, void *state )
1603 {
1604  struct _state *new_state = (struct _state *) state;
1605  struct _state *prev_state;
1606  size_t save_size;
1607 
1608  dbug_enter( "plbuf_switch" );
1609 
1610  // No saved state was passed, return a NULL--we hope the caller
1611  // is smart enough to notice
1612  //
1613  if ( state == NULL )
1614  return NULL;
1615 
1616  if ( !new_state->valid )
1617  {
1618  plwarn( "plbuf: Attempting to switch to an invalid saved state" );
1619  return NULL;
1620  }
1621 
1622  save_size = sizeof ( struct _state );
1623 
1624  if ( ( prev_state = (struct _state *) malloc( save_size ) ) == NULL )
1625  {
1626  plwarn( "plbuf: Unable to allocate memory to save state" );
1627  return NULL;
1628  }
1629 
1630  // Set some housekeeping variables
1631  prev_state->size = save_size;
1632  prev_state->valid = 1;
1633 
1634  // Preserve the existing state
1635  prev_state->plbuf_buffer = pls->plbuf_buffer;
1636  prev_state->plbuf_buffer_size = pls->plbuf_buffer_size;
1637  prev_state->plbuf_top = pls->plbuf_top;
1638  prev_state->plbuf_readpos = pls->plbuf_readpos;
1639 
1640  plbuf_restore( pls, new_state );
1641 
1642  return (void *) prev_state;
1643 }