1 //  Copyright (C) 1991, 1992, 1993, 1994, 1995  Geoffrey Furnish
2 //  Copyright (C) 1991, 1992, 1993, 1994, 1995  Maurice LeBrun
3 //
4 // PLplot is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU Library General Public License as published
6 // by the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // PLplot is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU Library General Public License for more details.
13 //
14 // You should have received a copy of the GNU Library General Public License
15 // along with PLplot; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 //
18 //--------------------------------------------------------------------------
19 //
20 //  This is a metafile writer for PLplot.
21 //
22 //
23 #include "plDevs.h"
24 
25 //#define DEBUG
26 
27 #ifdef PLD_plmeta
28 
29 #define NEED_PLDEBUG
30 #include "plplotP.h"
31 #include "drivers.h"
32 #include "metadefs.h"
33 #include <string.h>
34 
35 // Device info
36 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_plmeta = "plmeta:PLplot Native Meta-File:0:plmeta:26:plm\n";
37 
38 
39 void plD_dispatch_init_plm( PLDispatchTable *pdt );
40 
41 void plD_init_plm( PLStream * );
42 void plD_line_plm( PLStream *, short, short, short, short );
43 void plD_polyline_plm( PLStream *, short *, short *, PLINT );
44 void plD_eop_plm( PLStream * );
45 void plD_bop_plm( PLStream * );
46 void plD_tidy_plm( PLStream * );
47 void plD_state_plm( PLStream *, PLINT );
48 void plD_esc_plm( PLStream *, PLINT, void * );
49 
50 // Struct to hold device-specific info.
51 
52 // Used for constructing error messages
53 
54 #define BUFFER_LEN    256
55 
56 // Function prototypes
57 
58 static void WriteFileHeader( PLStream *pls );
59 static void UpdatePrevPagehdr( PLStream *pls );
60 static void WritePageInfo( PLStream *pls, FPOS_T pp_offset );
61 static void UpdateIndex( PLStream *pls, FPOS_T cp_offset );
62 static void plm_fill( PLStream *pls );
63 static void plm_swin( PLStream *pls );
64 static void plm_text( PLStream *pls, EscText *args );
65 
66 // A little function to help with debugging
67 
68 #ifdef DEBUG
69 #define DEBUG_PRINT_LOCATION( a )    PrintLocation( pls, a )
70 
PrintLocation(PLStream * pls,char * tag)71 static void PrintLocation( PLStream *pls, char *tag )
72 {
73     int isfile = ( pls->output_type == 0 );
74     if ( isfile )
75     {
76         FILE   *file = pls->OutFile;
77         FPOS_T current_offset;
78 
79         if ( pl_fgetpos( file, &current_offset ) )
80             plexit( "PrintLocation (plmeta.c): fgetpos call failed" );
81 
82         pldebug( tag, "at offset %d in file %s\n",
83             (int) current_offset, pls->FileName );
84     }
85 }
86 #else
87 #define DEBUG_PRINT_LOCATION( a )
88 #endif
89 
plD_dispatch_init_plm(PLDispatchTable * pdt)90 void plD_dispatch_init_plm( PLDispatchTable *pdt )
91 {
92 #ifndef ENABLE_DYNDRIVERS
93     pdt->pl_MenuStr = "PLplot Native Meta-File";
94     pdt->pl_DevName = "plmeta";
95 #endif
96     pdt->pl_type     = plDevType_FileOriented;
97     pdt->pl_seq      = 26;
98     pdt->pl_init     = (plD_init_fp) plD_init_plm;
99     pdt->pl_line     = (plD_line_fp) plD_line_plm;
100     pdt->pl_polyline = (plD_polyline_fp) plD_polyline_plm;
101     pdt->pl_eop      = (plD_eop_fp) plD_eop_plm;
102     pdt->pl_bop      = (plD_bop_fp) plD_bop_plm;
103     pdt->pl_tidy     = (plD_tidy_fp) plD_tidy_plm;
104     pdt->pl_state    = (plD_state_fp) plD_state_plm;
105     pdt->pl_esc      = (plD_esc_fp) plD_esc_plm;
106 }
107 
108 //--------------------------------------------------------------------------
109 // plD_init_plm()
110 //
111 // Initialize device.
112 //--------------------------------------------------------------------------
113 
114 void
plD_init_plm(PLStream * pls)115 plD_init_plm( PLStream *pls )
116 {
117     PLmDev *dev;
118 
119     dbug_enter( "plD_init_plm" );
120 
121     pls->color     = 1;         // Is a color device
122     pls->dev_fill0 = 1;         // Handle solid fills
123     pls->dev_fill1 = 1;         // Driver handles pattern fills
124 
125     if ( strncmp( PLMETA_VERSION, "2005", 4 ) == 0 )
126     {
127         pls->dev_text    = 0;       // Disable text handling by the driver
128         pls->dev_unicode = 0;       // Disable unicode support
129         pls->dev_hrshsym = 0;
130     }
131     else
132     {
133         // NOTE:  This breaks compatibility with the 2005 version of
134         // the plot metafile format
135         // Unicode support is not needed because the plmeta driver
136         // stores the unprocessed string data that was passed to PLplot.
137         // However, we turn it on to force unicode representation of the
138         // plot symbols in plsym.c rather than vectorization.
139         pls->dev_text    = 1;       // Enable text handling by the driver
140         pls->dev_unicode = 1;       // Enable unicode support
141         pls->dev_hrshsym = 0;       // Disable vectorizaton of Hershey symbols
142     }
143 
144 // Initialize family file info
145 
146     plFamInit( pls );
147 
148 // Prompt for a file name if not already set
149 
150     plOpenFile( pls );
151     pls->pdfs = pdf_finit( pls->OutFile );
152 
153 // Allocate and initialize device-specific data
154 
155     pls->dev = calloc( 1, (size_t) sizeof ( PLmDev ) );
156     if ( pls->dev == NULL )
157         plexit( "plD_init_plm: Out of memory." );
158 
159     dev = (PLmDev *) pls->dev;
160 
161     dev->xold = PL_UNDEFINED;
162     dev->yold = PL_UNDEFINED;
163 
164     dev->xmin = 0;
165     dev->xmax = PIXELS_X - 1;
166     dev->ymin = 0;
167     dev->ymax = PIXELS_Y - 1;
168 
169     dev->pxlx = (double) PIXELS_X / (double) LPAGE_X;
170     dev->pxly = (double) PIXELS_Y / (double) LPAGE_Y;
171 
172     plP_setpxl( dev->pxlx, dev->pxly );
173     plP_setphy( dev->xmin, dev->xmax, dev->ymin, dev->ymax );
174 
175 // Write Metafile header.
176 
177     WriteFileHeader( pls );
178 
179 // Write color map state info
180 
181     plD_state_plm( pls, PLSTATE_CMAP0 );
182     plD_state_plm( pls, PLSTATE_CMAP1 );
183 
184 // Write initialization command.
185 
186     DEBUG_PRINT_LOCATION( "before init" );
187     plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) INITIALIZE ) );
188 }
189 
190 //--------------------------------------------------------------------------
191 // plD_line_plm()
192 //
193 // Draw a line in the current color from (x1,y1) to (x2,y2).
194 //--------------------------------------------------------------------------
195 
196 void
plD_line_plm(PLStream * pls,short x1,short y1,short x2,short y2)197 plD_line_plm( PLStream *pls, short x1, short y1, short x2, short y2 )
198 {
199     PLmDev  *dev = (PLmDev *) pls->dev;
200     U_SHORT xy[4];
201 
202     // dbug_enter("plD_line_plm");
203 
204     // Failsafe check
205 
206 #ifdef DEBUG
207     if ( x1 < dev->xmin || x1 > dev->xmax ||
208          x2 < dev->xmin || x2 > dev->xmax ||
209          y1 < dev->ymin || y1 > dev->ymax ||
210          y2 < dev->ymin || y2 > dev->ymax )
211     {
212         pldebug( "plD_line_plm",
213             "coordinates out of bounds -- \nActual: (%i,%i), (%i,%i) Bounds: (%i,%i,%i,%i)\n",
214             x1, y1, x2, y2, dev->xmin, dev->xmax, dev->ymin, dev->ymax );
215     }
216 #endif
217 
218 // If continuation of previous line send the LINETO command, which uses
219 // the previous (x,y) point as it's starting location.  This results in a
220 // storage reduction of not quite 50%, since the instruction length for
221 // a LINETO is 5/9 of that for the LINE command, and given that most
222 // graphics applications use this command heavily.
223 //
224 // Still not quite as efficient as tektronix format since we also send the
225 // command each time (so shortest command is 25% larger), but a lot easier
226 // to implement than the tek method.
227 //
228     if ( x1 == dev->xold && y1 == dev->yold )
229     {
230         plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) LINETO ) );
231 
232         xy[0] = x2;
233         xy[1] = y2;
234         plm_wr( pdf_wr_2nbytes( pls->pdfs, xy, 2 ) );
235     }
236     else
237     {
238         plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) LINE ) );
239 
240         xy[0] = x1;
241         xy[1] = y1;
242         xy[2] = x2;
243         xy[3] = y2;
244         plm_wr( pdf_wr_2nbytes( pls->pdfs, xy, 4 ) );
245     }
246     dev->xold = x2;
247     dev->yold = y2;
248 }
249 
250 //--------------------------------------------------------------------------
251 // plD_polyline_plm()
252 //
253 // Draw a polyline in the current color.
254 //--------------------------------------------------------------------------
255 
256 void
plD_polyline_plm(PLStream * pls,short * xa,short * ya,PLINT npts)257 plD_polyline_plm( PLStream *pls, short *xa, short *ya, PLINT npts )
258 {
259     PLmDev *dev = (PLmDev *) pls->dev;
260 
261     dbug_enter( "plD_polyline_plm" );
262 
263     plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) POLYLINE ) );
264 
265     plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) npts ) );
266 
267     plm_wr( pdf_wr_2nbytes( pls->pdfs, (U_SHORT *) xa, npts ) );
268     plm_wr( pdf_wr_2nbytes( pls->pdfs, (U_SHORT *) ya, npts ) );
269 
270     dev->xold = xa[npts - 1];
271     dev->yold = ya[npts - 1];
272 }
273 
274 //--------------------------------------------------------------------------
275 // plD_eop_plm()
276 //
277 // End of page.
278 //--------------------------------------------------------------------------
279 
280 void
plD_eop_plm(PLStream * pls)281 plD_eop_plm( PLStream *pls )
282 {
283     plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) EOP ) );
284 }
285 
286 //--------------------------------------------------------------------------
287 // plD_bop_plm()
288 //
289 // Set up for the next page.
290 //
291 // Page header layout as follows:
292 //
293 // BOP			(U_CHAR)
294 // page number		(U_SHORT)
295 // prev page offset	(U_LONG)
296 // next page offset	(U_LONG)
297 //
298 // Each call after the first is responsible for updating the table of
299 // contents and the next page offset from the previous page.
300 //--------------------------------------------------------------------------
301 
302 void
plD_bop_plm(PLStream * pls)303 plD_bop_plm( PLStream *pls )
304 {
305     PLmDev *dev      = (PLmDev *) pls->dev;
306     int    isfile    = ( pls->output_type == 0 );
307     FPOS_T pp_offset = dev->lp_offset;
308 
309     dbug_enter( "plD_bop_plm" );
310 
311     dev->xold = PL_UNDEFINED;
312     dev->yold = PL_UNDEFINED;
313 
314 // Update previous page header
315 
316     if ( isfile )
317         UpdatePrevPagehdr( pls );
318 
319 // Start next family file if necessary.
320 
321     pls->bytecnt = pls->pdfs->bp;
322     plGetFam( pls );
323 
324 // Update page counter
325 
326     pls->page++;
327 
328 // Update table of contents info & write new page header.
329 
330     WritePageInfo( pls, pp_offset );
331 }
332 
333 //--------------------------------------------------------------------------
334 // plD_tidy_plm()
335 //
336 // Close graphics file
337 //--------------------------------------------------------------------------
338 
339 void
plD_tidy_plm(PLStream * pls)340 plD_tidy_plm( PLStream *pls )
341 {
342     dbug_enter( "plD_tidy_plm" );
343 
344     plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) CLOSE ) );
345     pdf_close( pls->pdfs );
346     free_mem( pls->dev );
347 }
348 
349 //--------------------------------------------------------------------------
350 // plD_state_plm()
351 //
352 // Handle change in PLStream state (color, pen width, fill attribute, etc).
353 //--------------------------------------------------------------------------
354 
355 void
plD_state_plm(PLStream * pls,PLINT op)356 plD_state_plm( PLStream *pls, PLINT op )
357 {
358     int i;
359 
360     dbug_enter( "plD_state_plm" );
361 
362     plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) CHANGE_STATE ) );
363     plm_wr( pdf_wr_1byte( pls->pdfs, op ) );
364 
365     switch ( op )
366     {
367     case PLSTATE_WIDTH:
368         plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) ( pls->width ) ) );
369         break;
370 
371     case PLSTATE_COLOR0:
372         plm_wr( pdf_wr_2bytes( pls->pdfs, (short) pls->icol0 ) );
373 
374         if ( pls->icol0 == PL_RGB_COLOR )
375         {
376             plm_wr( pdf_wr_1byte( pls->pdfs, pls->curcolor.r ) );
377             plm_wr( pdf_wr_1byte( pls->pdfs, pls->curcolor.g ) );
378             plm_wr( pdf_wr_1byte( pls->pdfs, pls->curcolor.b ) );
379         }
380         break;
381 
382     case PLSTATE_COLOR1:
383         plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->icol1 ) );
384         break;
385 
386     case PLSTATE_FILL:
387         plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) pls->patt ) );
388         break;
389 
390     case PLSTATE_CMAP0:
391         plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->ncol0 ) );
392         for ( i = 0; i < pls->ncol0; i++ )
393         {
394             plm_wr( pdf_wr_1byte( pls->pdfs, pls->cmap0[i].r ) );
395             plm_wr( pdf_wr_1byte( pls->pdfs, pls->cmap0[i].g ) );
396             plm_wr( pdf_wr_1byte( pls->pdfs, pls->cmap0[i].b ) );
397         }
398         break;
399 
400     case PLSTATE_CMAP1:
401         plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->ncol1 ) );
402         for ( i = 0; i < pls->ncol1; i++ )
403         {
404             plm_wr( pdf_wr_1byte( pls->pdfs, pls->cmap1[i].r ) );
405             plm_wr( pdf_wr_1byte( pls->pdfs, pls->cmap1[i].g ) );
406             plm_wr( pdf_wr_1byte( pls->pdfs, pls->cmap1[i].b ) );
407         }
408         break;
409 
410     case PLSTATE_CHR:
411         // save the chrdef and chrht parameters
412         if ( strncmp( PLMETA_VERSION, "2005", 4 ) != 0 )
413         {
414             plm_wr( pdf_wr_ieeef( pls->pdfs, (float) pls->chrdef ) );
415             plm_wr( pdf_wr_ieeef( pls->pdfs, (float) pls->chrht ) );
416         }
417         break;
418 
419     case PLSTATE_SYM:
420         // save the symdef and symht parameters
421         if ( strncmp( PLMETA_VERSION, "2005", 4 ) != 0 )
422         {
423             plm_wr( pdf_wr_ieeef( pls->pdfs, (float) pls->symdef ) );
424             plm_wr( pdf_wr_ieeef( pls->pdfs, (float) pls->symht ) );
425         }
426         break;
427     }
428 }
429 
430 //--------------------------------------------------------------------------
431 // plD_esc_plm()
432 //
433 // Escape function.  Note that any data written must be in device
434 // independent form to maintain the transportability of the metafile.
435 //
436 // Functions:
437 //
438 //	PLESC_FILL	Fill polygon
439 //	PLESC_SWIN	Set window parameters
440 //
441 //--------------------------------------------------------------------------
442 
443 void
plD_esc_plm(PLStream * pls,PLINT op,void * ptr)444 plD_esc_plm( PLStream *pls, PLINT op, void *ptr )
445 {
446     dbug_enter( "plD_esc_plm" );
447 
448     plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) ESCAPE ) );
449     plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) op ) );
450 
451     switch ( op )
452     {
453     case PLESC_FILL:
454         plm_fill( pls );
455         break;
456 
457     case PLESC_SWIN:
458         plm_swin( pls );
459         break;
460 
461     // Unicode and non-Unicode text handling
462     case PLESC_HAS_TEXT:
463         plm_text( pls, (EscText *) ptr );
464         break;
465 
466     // Alternate unicode text handling
467     case PLESC_BEGIN_TEXT:
468     case PLESC_TEXT_CHAR:
469     case PLESC_CONTROL_CHAR:
470     case PLESC_END_TEXT:
471         // NOP these for now until a decision is made
472         // which method should be implemented for metafiles
473         plwarn( "plmeta: Alternate Unicode text handling is not implemented" );
474         break;
475     }
476 }
477 
478 //--------------------------------------------------------------------------
479 // Private functions
480 //--------------------------------------------------------------------------
481 
482 //--------------------------------------------------------------------------
483 // plm_fill()
484 //
485 // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
486 //--------------------------------------------------------------------------
487 
488 static void
plm_fill(PLStream * pls)489 plm_fill( PLStream *pls )
490 {
491     PLmDev *dev = (PLmDev *) pls->dev;
492 
493     dbug_enter( "plm_fill" );
494 
495     plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->dev_npts ) );
496 
497     plm_wr( pdf_wr_2nbytes( pls->pdfs, (U_SHORT *) pls->dev_x, pls->dev_npts ) );
498     plm_wr( pdf_wr_2nbytes( pls->pdfs, (U_SHORT *) pls->dev_y, pls->dev_npts ) );
499 
500     dev->xold = PL_UNDEFINED;
501     dev->yold = PL_UNDEFINED;
502 }
503 
504 //--------------------------------------------------------------------------
505 // plm_swin()
506 //
507 // Set window parameters.
508 // Each parameter or group of parameters is tagged to make backward
509 // compatibility easier.
510 //--------------------------------------------------------------------------
511 
512 static void
plm_swin(PLStream * pls)513 plm_swin( PLStream *pls )
514 {
515     dbug_enter( "plm_swin" );
516 }
517 
518 //--------------------------------------------------------------------------
519 // plm_text()
520 //
521 // Stores the text into the metafile.
522 //--------------------------------------------------------------------------
523 
524 static void
plm_text(PLStream * pls,EscText * args)525 plm_text( PLStream *pls, EscText *args )
526 {
527     PLmDev *dev = (PLmDev *) pls->dev;
528     size_t len;
529 
530     // Write state information needed to render the text
531 
532     plm_wr( pdf_wr_ieeef( pls->pdfs, pls->chrht ) );
533     plm_wr( pdf_wr_ieeef( pls->pdfs, pls->diorot ) );
534     plm_wr( pdf_wr_2bytes( pls->pdfs, pls->clpxmi ) );
535     plm_wr( pdf_wr_2bytes( pls->pdfs, pls->clpxma ) );
536     plm_wr( pdf_wr_2bytes( pls->pdfs, pls->clpymi ) );
537     plm_wr( pdf_wr_2bytes( pls->pdfs, pls->clpyma ) );
538 
539     //  Write the text layout information
540 
541     plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) args->base ) );
542     plm_wr( pdf_wr_ieeef( pls->pdfs, (float) args->just ) );
543 
544     // Do we have a rotation shear that needs to be saved
545     if ( args->xform != NULL )
546     {
547         plm_wr( pdf_wr_ieeef( pls->pdfs, (float) args->xform[0] ) );
548         plm_wr( pdf_wr_ieeef( pls->pdfs, (float) args->xform[1] ) );
549         plm_wr( pdf_wr_ieeef( pls->pdfs, (float) args->xform[2] ) );
550         plm_wr( pdf_wr_ieeef( pls->pdfs, (float) args->xform[3] ) );
551     }
552     else
553     {
554         plwarn( "plmeta: transformation matrix undefined, using a guess" );
555         plm_wr( pdf_wr_ieeef( pls->pdfs, (float) 1.0 ) );
556         plm_wr( pdf_wr_ieeef( pls->pdfs, (float) 0.0 ) );
557         plm_wr( pdf_wr_ieeef( pls->pdfs, (float) 0.0 ) );
558         plm_wr( pdf_wr_ieeef( pls->pdfs, (float) 1.0 ) );
559     }
560 
561     plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) args->x ) );
562     plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) args->y ) );
563     plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) args->refx ) );
564     plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) args->refy ) );
565     plm_wr( pdf_wr_1byte( pls->pdfs, (U_CHAR) args->font_face ) );
566     plm_wr( pdf_wr_4bytes( pls->pdfs, (int) args->text_type ) );
567 
568     // Was a text string passed or a plot symbol?
569     if ( args->text_type == PL_STRING_TEXT )
570     {
571         // Text string
572         len = strlen( args->string );
573         plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) len ) );
574         if ( len > 0 )
575             plm_wr( pdf_wr_string( pls->pdfs, args->string ) );
576     }
577     else
578     {
579         // Plot symbol
580         plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) args->symbol ) );
581     }
582 
583     // Clear the last known position
584     dev->xold = PL_UNDEFINED;
585     dev->yold = PL_UNDEFINED;
586 }
587 
588 //--------------------------------------------------------------------------
589 // Provide a consistent method for handling a failed fsetpos.
590 //--------------------------------------------------------------------------
591 static void
handle_fsetpos_failed(const char * where,const char * which,FPOS_T position)592 handle_fsetpos_failed( const char *where, const char *which, FPOS_T position )
593 {
594     char buffer[BUFFER_LEN];
595 
596     // Format a standard message detailing the failure location
597     snprintf( buffer, BUFFER_LEN,
598         "%s: fsetpos to %s (%lu) failed",
599         where,
600         which,
601         (unsigned long) position );
602 
603     plexit( buffer );
604 }
605 
606 //--------------------------------------------------------------------------
607 // WriteFileHeader()
608 //
609 // Writes Metafile header.
610 //--------------------------------------------------------------------------
611 
612 static void
WriteFileHeader(PLStream * pls)613 WriteFileHeader( PLStream *pls )
614 {
615     PLmDev *dev   = (PLmDev *) pls->dev;
616     FILE   *file  = pls->OutFile;
617     int    isfile = ( pls->output_type == 0 );
618 
619     dbug_enter( "WriteFileHeader(PLStream *pls" );
620 
621     plm_wr( pdf_wr_header( pls->pdfs, PLMETA_HEADER ) );
622     plm_wr( pdf_wr_header( pls->pdfs, PLMETA_VERSION ) );
623 
624     // Write file index info.  Right now only number of pages.
625     // The order here is critical
626 
627     if ( isfile )
628     {
629         // Save the position of the pages field so that it can
630         // be updated when a new page is created
631         if ( pl_fgetpos( file, &dev->index_offset ) )
632             plexit( "WriteFileHeader: fgetpos call failed" );
633     }
634 
635     plm_wr( pdf_wr_header( pls->pdfs, "pages" ) );
636     plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) 0 ) );
637 
638     // Write initialization info.  Tag via strings to make backward
639     // compatibility with old metafiles as easy as possible.
640 
641     plm_wr( pdf_wr_header( pls->pdfs, "xmin" ) );
642     plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) dev->xmin ) );
643 
644     plm_wr( pdf_wr_header( pls->pdfs, "xmax" ) );
645     plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) dev->xmax ) );
646 
647     plm_wr( pdf_wr_header( pls->pdfs, "ymin" ) );
648     plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) dev->ymin ) );
649 
650     plm_wr( pdf_wr_header( pls->pdfs, "ymax" ) );
651     plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) dev->ymax ) );
652 
653     plm_wr( pdf_wr_header( pls->pdfs, "pxlx" ) );
654     plm_wr( pdf_wr_ieeef( pls->pdfs, (float) dev->pxlx ) );
655 
656     plm_wr( pdf_wr_header( pls->pdfs, "pxly" ) );
657     plm_wr( pdf_wr_ieeef( pls->pdfs, (float) dev->pxly ) );
658 
659     // Geometry info, needed to properly transmit e.g. aspect ratio, via the
660     // length params.  Not sure if the others are useful, but they're included
661     // for completeness.
662 
663     plm_wr( pdf_wr_header( pls->pdfs, "xdpi" ) );
664     plm_wr( pdf_wr_ieeef( pls->pdfs, (float) pls->xdpi ) );
665 
666     plm_wr( pdf_wr_header( pls->pdfs, "ydpi" ) );
667     plm_wr( pdf_wr_ieeef( pls->pdfs, (float) pls->ydpi ) );
668 
669     plm_wr( pdf_wr_header( pls->pdfs, "xlength" ) );
670     plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->xlength ) );
671 
672     plm_wr( pdf_wr_header( pls->pdfs, "ylength" ) );
673     plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->ylength ) );
674 
675     plm_wr( pdf_wr_header( pls->pdfs, "xoffset" ) );
676     plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->xoffset ) );
677 
678     plm_wr( pdf_wr_header( pls->pdfs, "yoffset" ) );
679     plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->yoffset ) );
680 
681     plm_wr( pdf_wr_header( pls->pdfs, "" ) );
682 }
683 
684 //--------------------------------------------------------------------------
685 // WritePageInfo()
686 //
687 // Update table of contents info & write new page header.
688 //--------------------------------------------------------------------------
689 
690 static void
WritePageInfo(PLStream * pls,FPOS_T pp_offset)691 WritePageInfo( PLStream *pls, FPOS_T pp_offset )
692 {
693     PLmDev *dev   = (PLmDev *) pls->dev;
694     FILE   *file  = pls->OutFile;
695     int    isfile = ( pls->output_type == 0 );
696     U_CHAR c;
697     FPOS_T cp_offset = 0;
698 
699     // Update table of contents.
700 
701     if ( isfile )
702     {
703         // Get the position of this page in order to update the index
704         if ( pl_fgetpos( file, &cp_offset ) )
705             plexit( "WritePageInfo (plmeta.c): fgetpos call failed" );
706 
707         UpdateIndex( pls, cp_offset );
708     }
709 
710     // Write new page header
711 
712     if ( dev->notfirst )
713         c = BOP;
714     else
715     {
716         c             = BOP0;
717         dev->notfirst = 1;
718     }
719     plm_wr( pdf_wr_1byte( pls->pdfs, c ) );
720     plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->page ) );
721     plm_wr( pdf_wr_4bytes( pls->pdfs, (U_LONG) pp_offset ) );
722     plm_wr( pdf_wr_4bytes( pls->pdfs, (U_LONG) 0 ) );
723 
724     // Update last page offset with current page value
725 
726     dev->lp_offset = cp_offset;
727 
728     // Write some page state information just to make things nice later on
729     // Eventually there will be more
730 
731     plD_state_plm( pls, PLSTATE_COLOR0 );
732 }
733 
734 //--------------------------------------------------------------------------
735 // UpdatePrevPagehdr()
736 //
737 // Update previous page header.
738 //--------------------------------------------------------------------------
739 
740 static void
UpdatePrevPagehdr(PLStream * pls)741 UpdatePrevPagehdr( PLStream *pls )
742 {
743     PLmDev *dev      = (PLmDev *) pls->dev;
744     FILE   *file     = pls->OutFile;
745     FPOS_T cp_offset = 0;
746 
747     fflush( file );
748 
749     // Determine where we are
750 
751     if ( pl_fgetpos( file, &cp_offset ) )
752         plexit( "plD_bop_plm: fgetpos call failed" );
753 
754     // Seek back to previous page header.
755 
756     if ( dev->lp_offset > 0 )
757     {
758         FPOS_T fwbyte_offset = 0;
759 
760         pldebug( "UpdatePrevPagehdr 1 (plmeta.c)",
761             "Location: %d, seeking to: %d\n",
762             (int) cp_offset, (int) dev->lp_offset );
763 
764         // The forward byte offset is located exactly 7 bytes after the BOP
765         fwbyte_offset = dev->lp_offset + 7;
766         if ( pl_fsetpos( file, &fwbyte_offset ) )
767         {
768             handle_fsetpos_failed( "UpdatePrevPagehdr",
769                 "fwbyte_offset", fwbyte_offset );
770         }
771 
772         // DEBUG: verify current location
773 
774 #ifdef DEBUG
775         if ( pl_fgetpos( file, &fwbyte_offset ) )
776             plexit( "UpdatePrevPagehdr (plmeta.c): fgetpos call failed" );
777 
778         pldebug( "UpdatePrevPagehdr 2 (plmeta.c)",
779             "Now at: %d, to write: %d\n",
780             (int) fwbyte_offset, (int) cp_offset );
781 #endif
782 
783         // Write forward byte offset into previous page header.
784 
785         plm_wr( pdf_wr_4bytes( pls->pdfs, (U_LONG) cp_offset ) );
786         fflush( file );
787 
788         // DEBUG: move back to before the write & read it to verify
789 
790 #ifdef DEBUG
791         if ( pl_fsetpos( file, &fwbyte_offset ) )
792         {
793             handle_fsetpos_failed( "UpdatePrevPagehdr",
794                 "fwbyte_offset", fwbyte_offset );
795         }
796         {
797             U_LONG read_offset;
798             plm_rd( pdf_rd_4bytes( pls->pdfs, &read_offset ) );
799             pldebug( "UpdatePrevPagehdr 3 (plmeta.c)",
800                 "Value read as: %d\n", read_offset );
801         }
802 #endif
803 
804         // Return to current page offset
805 
806         if ( pl_fsetpos( file, &cp_offset ) )
807         {
808             handle_fsetpos_failed( "UpdatePrevPagehdr",
809                 "cp_offset", cp_offset );
810         }
811     }
812 }
813 
814 //--------------------------------------------------------------------------
815 // UpdateIndex()
816 //
817 // Update file index.
818 //--------------------------------------------------------------------------
819 
820 static void
UpdateIndex(PLStream * pls,FPOS_T cp_offset)821 UpdateIndex( PLStream *pls, FPOS_T cp_offset )
822 {
823     PLmDev *dev  = (PLmDev *) pls->dev;
824     FILE   *file = pls->OutFile;
825 
826     // Update file index.  Right now only number of pages.
827     // The ordering here is critical
828 
829     if ( dev->index_offset > 0 )
830     {
831         pldebug( "UpdateIndex (plmeta.c)",
832             "Location: %d, seeking to: %d\n",
833             (int) cp_offset, (int) dev->lp_offset );
834 
835         if ( pl_fsetpos( file, &dev->index_offset ) )
836         {
837             handle_fsetpos_failed( "UpdateIndex",
838                 "index_offset", dev->index_offset );
839         }
840         plm_wr( pdf_wr_header( pls->pdfs, "pages" ) );
841         plm_wr( pdf_wr_2bytes( pls->pdfs, (U_SHORT) pls->page ) );
842 
843         pldebug( "UpdateIndex (plmeta.c)",
844             "Location: %d, seeking to: %d\n",
845             (int) dev->lp_offset, (int) cp_offset );
846 
847         if ( pl_fsetpos( file, &cp_offset ) )
848         {
849             handle_fsetpos_failed( "UpdateIndex",
850                 "cp_offset", cp_offset );
851         }
852     }
853 }
854 
855 #else
856 int
pldummy_plmeta()857 pldummy_plmeta()
858 {
859     return 0;
860 }
861 
862 #endif                          // PLD_plmeta
863