PLplot  5.11.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
plmetafile.c
Go to the documentation of this file.
1 // PLplot metafile I/O routines. Originally implemented in the plmeta
2 // driver and plrender. The decision was made to provide the capability
3 // to always read/write metafiles, thus the routines have been merged
4 // into the core of the library.
5 //
6 // Copyright (C) 2006 Hazen Babcock
7 // Copyright (C) 2015 Jim Dishaw
8 
9 //
10 // This file is part of PLplot.
11 //
12 // PLplot is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU Library General Public License as published
14 // by the Free Software Foundation; either version 2 of the License, or
15 // (at your option) any later version.
16 //
17 // PLplot is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU Library General Public License for more details.
21 //
22 // You should have received a copy of the GNU Library General Public License
23 // along with PLplot; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 //
26 //
27 
28 #define NEED_PLDEBUG
29 #include "plplotP.h"
30 #include "metadefs.h"
31 #include <stddef.h> // For the offsetof() macro
32 
33 #define MAX_BUFFER 256 // Character buffer size for reading records
34 
35 // Not all platforms support the lround() function and the coordinate system
36 // representation is going to be redone, thus this is just a placeholder until
37 // everything is sorted out.
38 #define PLFLT2COORD( a ) ( (short) ceil( a ) )
39 
40 // Status codes
42 {
51 };
52 
53 // Portable data format types (perhaps should be defined elsewhere?)
55 {
56  PDF_NULL = 0, // No-data type
57  PDF_UBYTE, // one-byte unsigned integer
58  PDF_USHORT, // two-byte unsigned integer
59  PDF_ULONG, // four-byte unsigned integer
60  PDF_IEEEF // IEEE 32 bit floating point
61 };
62 
63 // Data types used by PLplot (perhaps should be defined elsewhere?)
65 {
66  PLP_NULL = 0, // No-data type
74 };
75 
76 // Data format entry structure
78 {
79  char *name; // Name of the field
80  enum _pdf_types pdf_type; // Field data type in metafile
81  enum _plp_types plp_type; // Field data type in PLplot
82  const size_t offset; // Byte offset in the plmeta device
83 };
84 
85 // Metafile index information header
86 static const struct _plm_format index_2005_header[] = {
87  { "pages", PDF_USHORT, PLP_USHORT, offsetof( PLmIndex, pages ) },
88  // Last entry, do not change
89  { NULL, PDF_NULL, PLP_NULL, 0 }
90 };
91 
92 // Device information header
93 static const struct _plm_format dev_2005_header[] = {
94  { "xmin", PDF_USHORT, PLP_PLINT, offsetof( PLmDev, xmin ) },
95  { "xmax", PDF_USHORT, PLP_PLINT, offsetof( PLmDev, xmax ) },
96  { "ymin", PDF_USHORT, PLP_PLINT, offsetof( PLmDev, ymin ) },
97  { "ymax", PDF_USHORT, PLP_PLINT, offsetof( PLmDev, ymax ) },
98  { "pxlx", PDF_IEEEF, PLP_PLFLT, offsetof( PLmDev, pxlx ) },
99  { "pxly", PDF_IEEEF, PLP_PLFLT, offsetof( PLmDev, pxly ) },
100  // Last entry, do not change
101  { NULL, PDF_NULL, PLP_NULL, 0 }
102 };
103 
104 // Plot information header
105 static const struct _plm_format plot_2005_header[] = {
106  { "xdpi", PDF_IEEEF, PLP_PLFLT, offsetof( PLStream, xdpi ) },
107  { "ydpi", PDF_IEEEF, PLP_PLFLT, offsetof( PLStream, ydpi ) },
108  { "xlength", PDF_USHORT, PLP_PLINT, offsetof( PLStream, xlength ) },
109  { "ylength", PDF_USHORT, PLP_PLINT, offsetof( PLStream, ylength ) },
110  { "xoffset", PDF_USHORT, PLP_PLINT, offsetof( PLStream, xoffset ) },
111  { "yoffset", PDF_USHORT, PLP_PLINT, offsetof( PLStream, yoffset ) },
112  { "", PDF_NULL, PLP_NULL, 0 },
113  // Last entry, do not change
114  { NULL, 0, 0 }
115 };
116 
117 // Page information header
118 static const struct _plm_format page_2005_header[] = {
119  { "", PDF_USHORT, PLP_PLINT, offsetof( PLmDev, page ) },
120  { "", PDF_ULONG, PLP_PLINT, offsetof( PLmDev, lp_offset ) },
121  { "", PDF_ULONG, PLP_NULL, 0 }
122 };
123 
124 static struct _plm_version
125 {
126  const char *identifier;
127  const struct _plm_format *index_header;
128  const struct _plm_format *device_header;
129  const struct _plm_format *plot_header;
130 } metafile_format[] = {
131  { PLMETA_VERSION,
132  index_2005_header, dev_2005_header, plot_2005_header }
133 };
134 
135 static
137  void *dest, enum _plp_types type )
138 {
139  enum _plm_status rc = PLM_SUCCESS;
140 
141  switch ( type )
142  {
143  case PLP_NULL:
144  break;
145  case PLP_UBYTE:
146  *(uint8_t *) dest = x;
147  break;
148  case PLP_UCHAR:
149  *(unsigned char *) dest = x;
150  break;
151  case PLP_USHORT:
152  *(U_SHORT *) dest = x;
153  break;
154  case PLP_SHORT:
155  *(short *) dest = x;
156  break;
157  case PLP_PLINT:
158  *(PLINT *) dest = x;
159  break;
160  case PLP_PLFLT:
161  *(PLFLT *) dest = x;
162  break;
163  case PLP_ULONG:
164  *(U_LONG *) dest = x;
165  break;
166  default:
167  plwarn( "Unhandled datatype conversion in set_plp_value." );
169  break;
170  }
171 
172  return rc;
173 }
174 
175 static
177  void *dest, enum _plp_types type )
178 {
179  enum _plm_status rc = PLM_SUCCESS;
180 
181  switch ( type )
182  {
183  case PLP_NULL:
184  break;
185  case PLP_UBYTE:
186  *(uint8_t *) dest = x;
187  break;
188  case PLP_UCHAR:
189  *(unsigned char *) dest = x;
190  break;
191  case PLP_USHORT:
192  *(U_SHORT *) dest = x;
193  break;
194  case PLP_SHORT:
195  *(short *) dest = x;
196  break;
197  case PLP_PLINT:
198  *(PLINT *) dest = x;
199  break;
200  case PLP_PLFLT:
201  *(PLFLT *) dest = x;
202  break;
203  case PLP_ULONG:
204  *(U_LONG *) dest = x;
205  break;
206  default:
207  plwarn( "Unhandled datatype conversion in set_plp_value." );
209  break;
210  }
211 
212  return rc;
213 }
214 
215 static
216 enum _plm_status set_ulong_plp_value( unsigned long x,
217  void *dest, enum _plp_types type )
218 {
219  enum _plm_status rc = PLM_SUCCESS;
220 
221  switch ( type )
222  {
223  case PLP_NULL:
224  break;
225  case PLP_UBYTE:
226  *(uint8_t *) dest = x;
227  break;
228  case PLP_UCHAR:
229  *(unsigned char *) dest = x;
230  break;
231  case PLP_USHORT:
232  *(U_SHORT *) dest = x;
233  break;
234  case PLP_SHORT:
235  *(short *) dest = x;
236  break;
237  case PLP_PLINT:
238  *(PLINT *) dest = x;
239  break;
240  case PLP_PLFLT:
241  *(PLFLT *) dest = x;
242  break;
243  case PLP_ULONG:
244  *(U_LONG *) dest = x;
245  break;
246  default:
247  plwarn( "Unhandled datatype conversion in set_plp_value." );
249  break;
250  }
251 
252  return rc;
253 }
254 
255 static
257  void *dest, enum _plp_types type )
258 {
259  enum _plm_status rc = PLM_SUCCESS;
260 
261  switch ( type )
262  {
263  case PLP_NULL:
264  break;
265  case PLP_UBYTE:
266  *(uint8_t *) dest = x;
267  break;
268  case PLP_UCHAR:
269  *(unsigned char *) dest = x;
270  break;
271  case PLP_USHORT:
272  *(U_SHORT *) dest = x;
273  break;
274  case PLP_SHORT:
275  *(short *) dest = x;
276  break;
277  case PLP_PLINT:
278  *(PLINT *) dest = x;
279  break;
280  case PLP_PLFLT:
281  *(PLFLT *) dest = x;
282  break;
283  case PLP_ULONG:
284  *(U_LONG *) dest = x;
285  break;
286  default:
287  plwarn( "Unhandled datatype conversion in set_plp_value." );
289  break;
290  }
291 
292  return rc;
293 }
294 
295 static
297  enum _pdf_types from_type,
298  enum _plp_types to_type,
299  void *dest )
300 {
301  uint8_t b;
302  unsigned long l;
303  U_SHORT x;
304  float f;
305  enum _plm_status rc;
306  int pdf_rc;
307 
308  switch ( from_type )
309  {
310  case PLP_NULL:
311  pdf_rc = 0;
312  rc = PLM_SUCCESS;
313  break;
314 
315  case PDF_UBYTE: // Unsigned one-byte integer
316  if ( ( pdf_rc = pdf_rd_1byte( plm, &b ) ) == 0 )
317  rc = set_ubyte_plp_value( b, dest, to_type );
318  break;
319 
320  case PDF_USHORT: // Unsigned two-byte integer
321  if ( ( pdf_rc = pdf_rd_2bytes( plm, &x ) ) == 0 )
322  rc = set_ushort_plp_value( x, dest, to_type );
323  break;
324 
325  case PDF_ULONG: // Unsigned four-byte integer
326  if ( ( pdf_rc = pdf_rd_4bytes( plm, &l ) ) == 0 )
327  rc = set_ulong_plp_value( l, dest, to_type );
328  break;
329 
330  case PDF_IEEEF: // IEEE 32 bit float
331  if ( ( pdf_rc = pdf_rd_ieeef( plm, &f ) ) == 0 )
332  rc = set_ieeef_plp_value( f, dest, to_type );
333  break;
334 
335  default:
336  plwarn( "Unhandled datatype conversion in read_entry." );
338  break;
339  }
340 
341  if ( pdf_rc == 0 )
342  return rc;
343  else
344  return PLM_READ_ERROR;
345 }
346 
347 static
349  size_t bytes,
350  char *dest )
351 {
352  int rc;
353 
354  rc = pdf_rd_string( plm, dest, bytes );
355 
356  if ( rc == 0 )
357  return PLM_SUCCESS;
358  else
359  return PLM_READ_ERROR;
360 }
361 
362 //--------------------------------------------------------------------------
363 // read_metafile_header()
364 //
365 // Attempts to read the metafile header information in order to see if
366 // is a metafile and identify the version.
367 //--------------------------------------------------------------------------
368 static
370 {
371  char buffer[MAX_BUFFER];
372  PLINT version;
373  PLINT num_format_entries = sizeof ( metafile_format ) / sizeof ( struct _plm_version );
374 
375  dbug_enter( "read_metafile_enter()" );
376 
377  // Attempt to identify that this is a PLplot metafile
378  plm_rd( pdf_rd_header( plm, buffer ) );
379  if ( strcmp( buffer, PLMETA_HEADER ) != 0 )
380  {
381  return PLM_NOT_PLMETA_FILE;
382  }
383 
384  // Attempt to identify the version number
385  plm_rd( pdf_rd_header( plm, buffer ) );
386  for ( version = 0;
387  version < num_format_entries
388  && strcmp( metafile_format[version].identifier, buffer ) != 0;
389  version++ )
390  ;
391 
392  if ( version >= num_format_entries )
393  return ( PLM_UNKNOWN_VERSION );
394 
395  dev->version = version;
396 
397  return PLM_SUCCESS;
398 }
399 
400 static
401 void check_buffer_size( PLmDev *dev, size_t need_size )
402 {
403  // Do we have enough space?
404  if ( need_size > dev->buffer_size )
405  {
406  // Nope, free the current buffer if it is allocated
407  if ( dev->buffer != NULL )
408  free( dev->buffer );
409 
410  dev->buffer = malloc( need_size );
411  if ( dev->buffer == NULL )
412  {
413  plexit( "plmetafie: Insufficient memory for temporary storage" );
414  }
415  dev->buffer_size = need_size;
416  }
417 }
418 
419 //--------------------------------------------------------------------------
420 // read_header()
421 //
422 // Read a header block from the plot metafile.
423 //
424 // NOTE: Currently we enforce rigid adherence to the order
425 // specified by the format. This can be changed so that the
426 // entries a looked up instead.
427 //--------------------------------------------------------------------------
428 static
430  const struct _plm_format *header,
431  uint8_t * dest )
432 {
433  char buffer[MAX_BUFFER];
434  unsigned int entry;
435  enum _plm_status rc;
436 
437  for ( entry = 0;
438  header[entry].name != NULL;
439  entry++ )
440  {
441  // Get the name of this field and verify it is correct
442  plm_rd( pdf_rd_header( plm, buffer ) );
443  if ( strcmp( header[entry].name, buffer ) != 0 )
444  {
445  return PLM_FORMAT_ERROR;
446  }
447 
448  rc = read_entry( plm,
449  header[entry].pdf_type,
450  header[entry].plp_type,
451  dest + header[entry].offset );
452 
453  if ( rc != PLM_SUCCESS )
454  return rc;
455  }
456 
457  return PLM_SUCCESS;
458 }
459 
460 //--------------------------------------------------------------------------
461 // read_line()
462 //
463 // Process a LINE command from the metafile
464 //--------------------------------------------------------------------------
465 static
466 enum _plm_status read_line( PDFstrm *plm, PLmDev *dev, PLStream *pls )
467 {
468  PLFLT x1, y1, x2, y2;
469  short x[2], y[2];
470  enum _plm_status rc;
471 
472  // Read the start and end points
473  // The metafile stores the points as x,y pairs
474  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &x1 );
475  if ( rc != PLM_SUCCESS )
476  return rc;
477  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &y1 );
478  if ( rc != PLM_SUCCESS )
479  return rc;
480  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &x2 );
481  if ( rc != PLM_SUCCESS )
482  return rc;
483  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &y2 );
484  if ( rc != PLM_SUCCESS )
485  return rc;
486 
487  // Transform the coordinates from the meta device to the current
488  // device coordinate system
489  x[0] = PLFLT2COORD( dev->mfpcxa * x1 + dev->mfpcxb );
490  y[0] = PLFLT2COORD( dev->mfpcya * y1 + dev->mfpcyb );
491  x[1] = PLFLT2COORD( dev->mfpcxa * x2 + dev->mfpcxb );
492  y[1] = PLFLT2COORD( dev->mfpcya * y2 + dev->mfpcyb );
493 
494  // Draw the line
495  plP_line( x, y );
496 
497  // Preserve the last XY coords for the LINETO command
498  dev->xold = (short) x[1];
499  dev->yold = (short) y[1];
500 
501  return PLM_SUCCESS;
502 }
503 
504 //--------------------------------------------------------------------------
505 // read_lineto()
506 //
507 // Process a LINE command from the metafile
508 //--------------------------------------------------------------------------
509 static
511 {
512  PLFLT x2, y2;
513  short x[2], y[2];
514  int i;
515  enum _plm_status rc;
516 
517  // Set the start to the last known position
518  x[0] = (PLFLT) dev->xold;
519  y[0] = (PLFLT) dev->yold;
520 
521  // Read the end point
522  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &x2 );
523  if ( rc != PLM_SUCCESS )
524  return rc;
525  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &y2 );
526  if ( rc != PLM_SUCCESS )
527  return rc;
528 
529  // Transform the coordinates from the meta device to the current
530  // device coordinate system
531  x[1] = PLFLT2COORD( dev->mfpcxa * x2 + dev->mfpcxb );
532  y[1] = PLFLT2COORD( dev->mfpcya * y2 + dev->mfpcyb );
533 
534  // Draw the line
535  plP_line( x, y );
536 
537  // Preserve the last XY coords for the LINETO command
538  dev->xold = (short) x[1];
539  dev->yold = (short) y[1];
540 
541  return PLM_SUCCESS;
542 }
543 
544 //--------------------------------------------------------------------------
545 // read_polyline()
546 //
547 // Process a POLYLINE command from the metafile
548 //--------------------------------------------------------------------------
549 static
551 {
552  PLINT i, npts;
553  PLFLT x, y;
554  short *xd, *yd;
555  enum _plm_status rc;
556 
557  // Read the number of control points and put into the plot buffer
558  rc = read_entry( plm, PDF_USHORT, PLP_PLINT, &npts );
559  if ( rc != PLM_SUCCESS )
560  return rc;
561 
562  // Setup temporary storage. We need 2 * npts to store the X,Y pairs
563  check_buffer_size( dev, sizeof ( short ) * npts * 2 );
564  // Setup storage for the x values and y values
565  xd = (short *) ( dev->buffer );
566  yd = ( (short *) ( dev->buffer ) ) + npts;
567 
568  // Read the points and insert into the plot buffer
569  // The x values
570  for ( i = 0; i < npts; i++ )
571  {
572  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &x );
573  if ( rc != PLM_SUCCESS )
574  return rc;
575 
576  // Transform the coordinates from the meta device to the current
577  // device coordinate system
578  xd[i] = PLFLT2COORD( dev->mfpcxa * x + dev->mfpcxb );
579  }
580  // Preserve the last X value for the LINETO command
581  dev->xold = xd[npts - 1];
582 
583  // The y values
584  for ( i = 0; i < npts; i++ )
585  {
586  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &y );
587  if ( rc != PLM_SUCCESS )
588  return rc;
589 
590  // Transform the coordinates from the meta device to the current
591  // device coordinate system
592  yd[i] = PLFLT2COORD( dev->mfpcya * y + dev->mfpcyb );
593  }
594  // Preserve the last Y value for the LINETO command
595  dev->yold = yd[npts - 1];
596 
597  // Draw the line
598  plP_polyline( xd, yd, npts );
599 
600  return PLM_SUCCESS;
601 }
602 
603 //--------------------------------------------------------------------------
604 // read_escape()
605 //
606 // Process a escape command from the metafile
607 //--------------------------------------------------------------------------
608 static
610 {
611  uint8_t op;
612  enum _plm_status rc = PLM_SUCCESS;
613 
614  // Read the state operation, return if an error
615  if ( pdf_rd_1byte( plm, &op ) != 0 )
616  return PLM_FORMAT_ERROR;
617 
618  switch ( op )
619  {
620  case PLESC_FILL:
621  {
622  PLINT i, npts;
623  PLFLT x, y;
624  short *xd, *yd;
625 
626  // Get the number of control points for the fill
627  rc = read_entry( plm, PDF_USHORT, PLP_PLINT, &npts );
628  if ( rc != PLM_SUCCESS )
629  return rc;
630 
631  // Setup temporary storage. We need 2 * npts to store the X,Y pairs
632  check_buffer_size( dev, sizeof ( short ) * npts * 2 );
633  // Setup storage for the x values and y values
634  xd = (short *) ( dev->buffer );
635  yd = ( (short *) ( dev->buffer ) ) + npts;
636 
637  for ( i = 0; i < npts; i++ )
638  {
639  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &x );
640  if ( rc != PLM_SUCCESS )
641  return rc;
642 
643  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &y );
644  if ( rc != PLM_SUCCESS )
645  return rc;
646 
647  // Transform the coordinates from the meta device to the current
648  // device coordinate system
649  xd[i] = PLFLT2COORD( dev->mfpcxa * x + dev->mfpcxb );
650  yd[i] = PLFLT2COORD( dev->mfpcya * y + dev->mfpcyb );
651  }
652 
653  plP_fill( xd, yd, npts );
654  }
655  break;
656 
657  case PLESC_SWIN:
658  rc = PLM_SUCCESS;
659  break;
660 
661 
662  // Text handling. The metafile contains unprocessed string
663  // data
664  case PLESC_HAS_TEXT:
665  {
666  EscText text;
667  PLFLT xform[4];
668  PLUNICODE fci, ch;
669  PLINT i;
670  PLFLT xmin, xmax, ymin, ymax;
671  PLFLT x, y, refx, refy;
672  size_t len;
673 
674  // Setup storage for the transformation matrix
675  text.xform = xform;
676 
677  // Read the information from the metafile
678  rc = read_entry( plm, PDF_IEEEF, PLP_PLFLT, &pls->chrht );
679  rc = read_entry( plm, PDF_IEEEF, PLP_PLFLT, &pls->diorot );
680  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &xmin );
681  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &xmax );
682  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &ymin );
683  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &ymax );
684 
685  rc = read_entry( plm, PDF_USHORT, PLP_PLINT, &text.base );
686  rc = read_entry( plm, PDF_IEEEF, PLP_PLFLT, &text.just );
687  rc = read_entry( plm, PDF_IEEEF, PLP_PLFLT, &text.xform[0] );
688  rc = read_entry( plm, PDF_IEEEF, PLP_PLFLT, &text.xform[1] );
689  rc = read_entry( plm, PDF_IEEEF, PLP_PLFLT, &text.xform[2] );
690  rc = read_entry( plm, PDF_IEEEF, PLP_PLFLT, &text.xform[3] );
691  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &x );
692  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &y );
693  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &refx );
694  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &refy );
695  rc = read_entry( plm, PDF_UBYTE, PLP_UCHAR, &text.font_face );
696 
697  // Check for a size mismatch that indicates a problem in the
698  // library that the developers need to fix
699  if ( sizeof ( text.text_type ) != sizeof ( U_LONG ) )
700  {
701  plwarn( "plmetafile: Serious library error! text_type != U_LONG" );
702  return PLM_FORMAT_ERROR;
703  }
704  rc = read_entry( plm, PDF_ULONG, PLP_ULONG, &text.text_type );
705 
706  // Translate coordinates to the device coordinate system
707  pls->clpxmi = PLFLT2COORD( dev->mfpcxa * xmin + dev->mfpcxb );
708  pls->clpxma = PLFLT2COORD( dev->mfpcxa * xmax + dev->mfpcxb );
709  pls->clpymi = PLFLT2COORD( dev->mfpcxa * ymin + dev->mfpcxb );
710  pls->clpyma = PLFLT2COORD( dev->mfpcxa * ymax + dev->mfpcxb );
711 
712  text.x = PLFLT2COORD( dev->mfpcxa * x + dev->mfpcxb );
713  text.y = PLFLT2COORD( dev->mfpcya * y + dev->mfpcyb );
714  text.refx = PLFLT2COORD( dev->mfpcxa * refx + dev->mfpcxb );
715  text.refy = PLFLT2COORD( dev->mfpcya * refy + dev->mfpcyb );
716 
717  if ( text.text_type == PL_STRING_TEXT )
718  {
719  // Retrieve the text string
720  rc = read_entry( plm, PDF_USHORT, PLP_ULONG, &len );
721 
722  // Add one to the length for the NUL character. The metafile
723  // format stores the NUL, so we must read it.
724  len++;
725 
726  // Check that we have enough storage for the string
727  check_buffer_size( dev, len * sizeof ( char ) );
728 
729  // Read the string from the metafile
730  rc = read_string( plm, len, dev->buffer );
731 
732  text.string = (char *) dev->buffer;
733 
734  // Call the text rendering routine
735  plP_text(
736  text.base, text.just, text.xform,
737  text.x, text.y,
738  text.refx, text.refy,
739  text.string );
740  }
741  else
742  {
743  rc = read_entry( plm, PDF_USHORT, PLP_PLINT, &text.symbol );
744  plhrsh( text.symbol, text.x, text.y );
745  }
746  }
747  rc = PLM_SUCCESS;
748  break;
749 
750  // Alternate unicode text handling
751  case PLESC_BEGIN_TEXT:
752  case PLESC_TEXT_CHAR:
753  case PLESC_CONTROL_CHAR:
754  case PLESC_END_TEXT:
755  // NOP these for now until a decision is made
756  // which method should be implemented for metafiles
757  plwarn( "plmetafile: Alternate Unicode text handling is not implemented" );
758  rc = PLM_INVALID_CMD;
759  break;
760 
761  default:
762  break;
763  }
764 
765  return rc;
766 }
767 
768 //--------------------------------------------------------------------------
769 // read_state()
770 //
771 // Process a state command from the metafile
772 //--------------------------------------------------------------------------
773 static
774 enum _plm_status read_state( PDFstrm *plm, PLmDev *dev, PLStream *pls )
775 {
776  uint8_t op;
777  enum _plm_status rc = PLM_SUCCESS;
778 
779  // Read the state operation, return if an error
780  if ( pdf_rd_1byte( plm, &op ) != 0 )
781  return PLM_FORMAT_ERROR;
782 
783  switch ( op )
784  {
785  case PLSTATE_WIDTH:
786  pldebug( "state: WIDTH" );
787 
788  rc = read_entry( plm, PDF_USHORT, PLP_PLFLT, &( pls->width ) );
789  if ( rc != PLM_SUCCESS )
790  return rc;
791 
792  break;
793 
794  case PLSTATE_COLOR0:
795  case PLSTATE_COLOR1:
796  pldebug( "state: COLOR0/COLOR1" );
797 
798  {
799  PLINT icol;
800 
801  // Read the color index number
802  rc = read_entry( plm, PDF_USHORT, PLP_PLINT, &icol );
803  if ( rc != PLM_SUCCESS )
804  return rc;
805 
806  // Was pen 0 set to an RGB value rather than color index?
807  if ( op == PLSTATE_COLOR0 && icol != PL_RGB_COLOR )
808  {
809  pls->icol0 = icol;
810  pls->curcolor.r = pls->cmap0[icol].r;
811  pls->curcolor.g = pls->cmap0[icol].g;
812  pls->curcolor.b = pls->cmap0[icol].b;
813  pls->curcolor.a = pls->cmap0[icol].a;
814  }
815  else if ( op == PLSTATE_COLOR1 )
816  {
817  pls->icol1 = icol;
818  pls->curcolor.r = pls->cmap1[icol].r;
819  pls->curcolor.g = pls->cmap1[icol].g;
820  pls->curcolor.b = pls->cmap1[icol].b;
821  pls->curcolor.a = pls->cmap1[icol].a;
822  }
823  else
824  {
825  // Get the RGB value and copy to the plot buffer
826  PLColor color;
827 
828  rc = read_entry( plm, PDF_UBYTE, PLP_UCHAR, &color.r );
829  if ( rc != PLM_SUCCESS )
830  return rc;
831 
832  rc = read_entry( plm, PDF_UBYTE, PLP_UCHAR, &color.g );
833  if ( rc != PLM_SUCCESS )
834  return rc;
835 
836  rc = read_entry( plm, PDF_UBYTE, PLP_UCHAR, &color.b );
837  if ( rc != PLM_SUCCESS )
838  return rc;
839 
840  pls->icol0 = icol;
841  pls->curcolor.r = color.r;
842  pls->curcolor.g = color.g;
843  pls->curcolor.b = color.b;
844  pls->curcolor.a = 1.0;
845  }
846  }
847  break;
848 
849  case PLSTATE_FILL:
850  pldebug( "state: FILL" );
851 
852  // Read the pattern and put into the plot buffer
853  rc = read_entry( plm, PDF_USHORT, PLP_UCHAR, &( pls->patt ) );
854  if ( rc != PLM_SUCCESS )
855  return rc;
856 
857  break;
858 
859  case PLSTATE_CMAP0:
860  case PLSTATE_CMAP1:
861  pldebug( "state: CMAP0/CMAP1" );
862 
863  {
864  PLINT i, ncol;
865  PLINT *r, *g, *b;
866  PLFLT *alpha;
867  void *ptr;
868 
869  // Read the number of colors
870  rc = read_entry( plm, PDF_USHORT, PLP_PLINT, &ncol );
871  if ( rc != PLM_SUCCESS )
872  return rc;
873 
874  // Check that temporary storage is sized correctly
876  dev,
877  sizeof ( PLINT ) * ncol * 3 // R, G, B values
878  + sizeof ( PLFLT ) * ncol ); // alpha channel values
879  ptr = dev->buffer;
880  r = (PLINT *) ptr;
881  ptr = ( (PLINT *) ptr ) + ncol;
882  g = (PLINT *) ptr;
883  ptr = ( (PLINT *) ptr ) + ncol;
884  b = (PLINT *) ptr;
885  ptr = ( (PLINT *) ptr ) + ncol;
886  alpha = (PLFLT *) ptr;
887 
888  // Read the colormap
889  for ( i = 0; i < ncol; i++ )
890  {
891  rc = read_entry( plm, PDF_UBYTE, PLP_PLINT, &( r[i] ) );
892  if ( rc != PLM_SUCCESS )
893  return rc;
894 
895  rc = read_entry( plm, PDF_UBYTE, PLP_PLINT, &( g[i] ) );
896  if ( rc != PLM_SUCCESS )
897  return rc;
898 
899  rc = read_entry( plm, PDF_UBYTE, PLP_PLINT, &( b[i] ) );
900  if ( rc != PLM_SUCCESS )
901  return rc;
902 
903  alpha[i] = 1.0;
904  }
905 
906  // Call the colormap API so that memory is correctly allocated
907  // instead of plP_state( PLSTATE_CMAP0 );
908  if ( op == PLSTATE_CMAP0 )
909  plscmap0a( r, g, b, alpha, ncol );
910  else
911  plscmap1a( r, g, b, alpha, ncol );
912 
913  // Return here because plscmap0a and plscmap1a call
914  // plP_state( PLSTATE_CMAP0 or PLSTATE_CMAP1 )
915  return PLM_SUCCESS;
916  }
917  break;
918 
919  case PLSTATE_CHR:
920  pldebug( "state: CHR" );
921 
922  // The 2005 version and earlier do not support this operation
923  if ( 1 )
924  {
925  rc = read_entry( plm, PDF_IEEEF, PLP_PLFLT, &( pls->chrdef ) );
926  if ( rc != PLM_SUCCESS )
927  return rc;
928 
929  rc = read_entry( plm, PDF_IEEEF, PLP_PLFLT, &( pls->chrht ) );
930  if ( rc != PLM_SUCCESS )
931  return rc;
932  }
933  break;
934 
935  case PLSTATE_SYM:
936  pldebug( "state: SYM" );
937 
938  // The 2005 version and earlier do not support this operation
939  if ( 1 )
940  {
941  rc = read_entry( plm, PDF_IEEEF, PLP_PLFLT, &( pls->symdef ) );
942  if ( rc != PLM_SUCCESS )
943  return rc;
944 
945  rc = read_entry( plm, PDF_IEEEF, PLP_PLFLT, &( pls->symht ) );
946  if ( rc != PLM_SUCCESS )
947  return rc;
948  }
949  break;
950 
951  default:
952  pldebug( "state: INVALID STATE" );
953  return PLM_INVALID_STATE;
954  }
955 
956  plP_state( op );
957 
958  return PLM_SUCCESS;
959 }
960 
961 //--------------------------------------------------------------------------
962 // read_plot_commands()
963 //
964 // Reads the plot commands from the metafile and places them into the
965 // plot buffer
966 //--------------------------------------------------------------------------
967 static
969 {
970  uint8_t cmd;
971  enum _plm_status rc = PLM_SUCCESS;
972 
973  dbug_enter( "read_plot_commands()" );
974 
975  // Read the metafile until a non-zero result occurs, which typically
976  // indicates an end-of-file condition
977  while ( rc == PLM_SUCCESS && pdf_rd_1byte( plm, &cmd ) == 0 )
978  {
979  switch ( cmd )
980  {
981  case INITIALIZE:
982  pldebug( "cmd: INITIALIZE" );
983  // No action needed
984  break;
985 
986  case CLOSE:
987  pldebug( "cmd: CLOSE" );
988  // No action needed
989  break;
990 
991  case EOP:
992  pldebug( "cmd: EOP" );
993 
994  plP_eop();
995  break;
996 
997  case BOP:
998  case BOP0: // First BOP in a file
999  pldebug( "cmd: BOP/BOP0" );
1000 
1001  // Read the metadata for this page
1002  rc = read_entry( plm,
1003  page_2005_header[0].pdf_type,
1004  page_2005_header[0].plp_type,
1005  (uint8_t *) dev + page_2005_header[0].offset );
1006  if ( rc != PLM_SUCCESS )
1007  break;
1008 
1009  rc = read_entry( plm,
1010  page_2005_header[1].pdf_type,
1011  page_2005_header[1].plp_type,
1012  (uint8_t *) dev + page_2005_header[1].offset );
1013  if ( rc != PLM_SUCCESS )
1014  break;
1015 
1016  rc = read_entry( plm,
1017  page_2005_header[2].pdf_type,
1018  page_2005_header[2].plp_type,
1019  (uint8_t *) dev + page_2005_header[2].offset );
1020  if ( rc != PLM_SUCCESS )
1021  break;
1022 
1023  plP_bop();
1024 
1025  break;
1026 
1027  case LINE:
1028  pldebug( "cmd: LINE" );
1029 
1030  rc = read_line( plm, dev, pls );
1031  break;
1032 
1033  case LINETO:
1034  pldebug( "cmd: LINETO" );
1035 
1036  rc = read_lineto( plm, dev, pls );
1037  break;
1038 
1039  case ESCAPE:
1040  pldebug( "cmd: ESCAPE" );
1041 
1042  rc = read_escape( plm, dev, pls );
1043  break;
1044 
1045  case POLYLINE:
1046  pldebug( "cmd: POLYLINE" );
1047 
1048  rc = read_polyline( plm, dev, pls );
1049  break;
1050 
1051  case CHANGE_STATE:
1052  pldebug( "cmd: CHANGE_STATE" );
1053 
1054  rc = read_state( plm, dev, pls );
1055  break;
1056 
1057  case END_OF_FIELD:
1058  pldebug( "cmd: EOF" );
1059 
1060  // No action needed
1061 
1062  break;
1063 
1064  case SWITCH_TO_TEXT: // Obsolete, replaced by ESCAPE
1065  case SWITCH_TO_GRAPH: // Obsolete, replaced by ESCAPE
1066  case NEW_COLOR: // Obsolete, replaced by CHANGE_STATE
1067  case NEW_WIDTH: // Obsolete, replaced by CHANGE_STATE
1068  case ADVANCE: // Obsolete, BOP/EOP used instead
1069  case NEW_COLOR1:
1070  pldebug( "cmd: OBSOLETE CMD" );
1071  plabort( "OBSOLETE CMD" );
1072 
1073  break;
1074 
1075  default:
1076  pldebug( "cmd: INVALID CMD" );
1077  plabort( "INVALID CMD" );
1078 
1079  return PLM_INVALID_CMD;
1080  }
1081  }
1082 
1083  return PLM_SUCCESS;
1084 }
1085 
1086 static
1087 void setup_page( PLmDev *mf_dev, PLStream *pls )
1088 {
1089  PLmDev *dev = pls->dev;
1090 
1091  mf_dev->mfpcxa = (PLFLT) dev->xlen
1092  / (PLFLT) ( mf_dev->xmax - mf_dev->xmin );
1093  mf_dev->mfpcxb = (PLFLT) dev->xmin;
1094  mf_dev->mfpcya = (PLFLT) dev->ylen
1095  / (PLFLT) ( mf_dev->ymax - mf_dev->ymin );
1096  mf_dev->mfpcyb = (PLFLT) dev->ymin;
1097 }
1098 
1099 //--------------------------------------------------------------------------
1100 // plreadmetafile()
1101 //
1114 //--------------------------------------------------------------------------
1115 void plreadmetafile( char *infile )
1116 {
1117  PDFstrm *plm;
1118  PLStream mf_pls;
1119  PLmDev mf_dev;
1120  PLmIndex index;
1121  enum _plm_status rc;
1122 
1123  if ( plsc->mf_infile == NULL && infile == NULL )
1124  {
1125  plexit( "No PLplot metafile set for input" );
1126  }
1127  else if ( infile != NULL )
1128  {
1129  plm = pdf_fopen( infile, "rb" );
1130  }
1131  else
1132  {
1133  plm = pdf_fopen( plsc->mf_infile, "rb" );
1134  }
1135  if ( plm == NULL )
1136  {
1137  plexit( "Unable to open PLplot metafile for input" );
1138  }
1139 
1140  // Intialize the metafile device
1141  mf_dev.buffer = NULL;
1142  mf_dev.buffer_size = 0;
1143 
1144  // Read the file header
1145  if ( ( rc = read_metafile_header( plm, &mf_dev ) ) != PLM_SUCCESS )
1146  {
1147  pdf_close( plm );
1148  plwarn( "Failed to parse PLplot metafile, ignoring file." );
1149  return;
1150  }
1151 
1152  // Read the index header
1153  rc = read_header( plm,
1155  (U_CHAR *) &index );
1156  if ( rc != PLM_SUCCESS )
1157  {
1158  pdf_close( plm );
1159  plwarn( "Corrupted index in metafile, ignoring file." );
1160  return;
1161  }
1162 
1163  // Read the device header
1164  rc = read_header( plm,
1166  (U_CHAR *) &mf_dev );
1167  if ( rc != PLM_SUCCESS )
1168  {
1169  pdf_close( plm );
1170  plwarn( "Corrupted device information in metafile, ignoring file." );
1171  return;
1172  }
1173 
1174  // Read the plot header into a local version of a plot stream.
1175  // We do this because some of the parameters from the metafile may
1176  // be invalid or inappropriate for the current plot device
1177  // (e.g. xlength = 0). The plspage() call should be smart enough
1178  // to setup the page correctly.
1179  rc = read_header( plm,
1181  (U_CHAR *) &mf_pls );
1182  if ( rc != PLM_SUCCESS )
1183  {
1184  pdf_close( plm );
1185  plwarn( "Corrupted device information in metafile, ignoring file." );
1186  return;
1187  }
1188 
1189  // Is the plot stream initialized?
1190  if ( plsc->level == 0 )
1191  {
1192  // No, we must intialize it in order to get the
1193  // device configuation set
1194  plinit();
1195  }
1196  setup_page( &mf_dev, plsc );
1197 
1198  // At this point we should be in the plot commands
1199  rc = read_plot_commands( plm, &mf_dev, plsc );
1200  if ( rc != PLM_SUCCESS )
1201  {
1202  pdf_close( plm );
1203  plwarn( "Corrupted plot information in metafile, ignoring file." );
1204  return;
1205  }
1206 
1207  pdf_close( plm );
1208 
1209  // Free the temporary storage
1210  if ( mf_dev.buffer != NULL )
1211  free( mf_dev.buffer );
1212 }