1 /*@z48.c:PDF back end@********************************************************/
2 /*                                                                           */
3 /*  THE LOUT DOCUMENT FORMATTING SYSTEM (VERSION 3.39)                       */
4 /*  COPYRIGHT (C) 1991, 2008 Jeffrey H. Kingston                             */
5 /*                                                                           */
6 /*  Jeffrey H. Kingston (jeff@it.usyd.edu.au)                                */
7 /*  School of Information Technologies                                       */
8 /*  The University of Sydney 2006                                            */
9 /*  AUSTRALIA                                                                */
10 /*                                                                           */
11 /*  This PDF Back End module written by Vincent Tan, March 1998.             */
12 /*                                                                           */
13 /*  This program is free software; you can redistribute it and/or modify     */
14 /*  it under the terms of the GNU General Public License as published by     */
15 /*  the Free Software Foundation; either Version 3, or (at your option)      */
16 /*  any later version.                                                       */
17 /*                                                                           */
18 /*  This program is distributed in the hope that it will be useful,          */
19 /*  but WITHOUT ANY WARRANTY; without even the implied warranty of           */
20 /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the            */
21 /*  GNU General Public License for more details.                             */
22 /*                                                                           */
23 /*  You should have received a copy of the GNU General Public License        */
24 /*  along with this program; if not, write to the Free Software              */
25 /*  Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA   */
26 /*                                                                           */
27 /*  FILE:         z48.c                                                      */
28 /*  MODULE:       PDF back end                                               */
29 /*  EXTERNS:      PDFFile_Init(), PDFFile_BeginFontEncoding(),               */
30 /*                PDFFile_EndFontEncoding(), PDFFile_Cleanup(),              */
31 /*                PDFPage_Init(), PDFPage_Cleanup(), PDFPage_Write(),        */
32 /*                PDFPage_Push(), PDFPage_Pop(), PDFPage_Scale(),            */
33 /*                PDFPage_Translate(), PDFPage_Rotate(), PDFPage_SetVars(),  */
34 /*                PDFPage_WriteGraphic(), PDFPage_PrintUnderline(),          */
35 /*                PDFFont_AddFont(), PDFFont_Set(), PDFText_OpenXY(),        */
36 /*                PDFText_OpenX(), PDFText_Open(), PDFText_Kern(),           */
37 /*                PDFText_Close(), PDFHasValidTextMatrix()                   */
38 /*                                                                           */
39 /*****************************************************************************/
40 #include "externs.h"
41 
42 /* ANSI headers */
43 #include <ctype.h>
44 #include <math.h>
45 #ifndef M_PI
46 #define M_PI 3.14159265358979323846
47 #endif
48 #include <time.h>
49 
50 /* zlib headers: define PDF_COMPRESSION = 0 if you don't have zlib library */
51 #if PDF_COMPRESSION
52 #include "zlib.h"
53 #endif
54 
Assert(BOOLEAN condition,FILE_POS * inFilePos)55 static void Assert(BOOLEAN condition, FILE_POS *inFilePos)
56 {
57   if (!condition)		/* allows me to set a breakpoint here */
58   assert(condition, inFilePos);
59 }
60 
61 /* #define's and typedefs */
62 #undef USE_MATRICES
63 #undef _CALC_LARGEST_PAGE_OBJECT_
64 
65 enum {
66   kBase14FontCount = 14,    /* there are 14 base PDF fonts */
67   kBufferSize = 1024	    /* size of buffer for skipping non-marking commands */
68 };
69 
70 #if PDF_COMPRESSION
71 enum {
72   kRawOutputBufferSize = 4096,		/* arbitrary choice */
73   kCompressedOutputBufferSize = 4096	/* arbitrary choice */
74 };
75 #endif
76 
77 enum {
78   kNumberOfObjectsPerBlock = 256,	/* arbitrary choice */
79   kNumberOfPagesPerBlock = 64		/* arbitrary choice */
80 };
81 
82 typedef enum {
83   kFitNoChange = 0,	/* special default case */
84   kFit,			/* [ /Fit ]: fit the page to the window */
85   kFitH,		/* [ /FitH top ]: fit the width of the page to window; */
86 			/* top specifies y-coord of the top edge of the window */
87   kFitV,		/* [ /FitV left ]: fit the height of the page to the   */
88 			/* window. left specifies x-coord of left edge of win. */
89   kFitR,		/* [ /FitR left bottom right top ]: fit the rectangle  */
90 			/* specified by left bottom right top in the window.   */
91 			/* If the height (top - bottom) and width (right-left) */
92 			/* imply different zoom factors, the numerically       */
93 			/* smaller zoom factor is used, to ensure that the     */
94 			/* specified rectangle fits in the window              */
95   kFitB,		/* [ /FitB ]: fit the page's bounding box to window    */
96   kFitBH,		/* [ /FitBH top ]: fit the width of the page's bound.  */
97 			/* box to the window. top specifies the y-coordinate   */
98 			/* of the top edge of the window                       */
99   kFitBV,		/* [ /FitBV left ]: fit the height of the page's       */
100 			/* bounding box to the window. left specifies the      */
101 			/* x-coordinate of the left edge of the window         */
102 
103   kNumberOfDestLinkOptions
104 } PDF_LINK_DEST_OPTION;
105 
106 enum eUnitsKeywords {
107   k_in = 0,
108   k_cm,
109   k_pt,
110   k_em,
111   k_loutf,
112   k_loutv,
113   k_louts,
114   kNumberOfUnitKeywords
115 };
116 
117 enum eGraphicsKeywords {
118   k_xsize = 0,
119   k_ysize,
120   k_xmark,
121   k_ymark,
122   kNumberOfGraphicsKeywords
123 };
124 
125 enum eArithmeticKeywords {
126   k_add = 0,
127   k_sub,
128   k_mul,
129   k_div,
130   k_sin,
131   k_cos,
132   k_pick,
133   kNumberOfArithmeticKeywords
134 };
135 
136 typedef enum {
137   k_link_source = 0,	/* source of a link to an internal document target */
138   k_link_external,	/* source of a link to an external document target */
139   k_link_URI,		/* source of a link to an (external) URI target    */
140   k_link_target,	/* internal document target                        */
141   k_link_target_for_export,	/* external document target                */
142   kNumberOfLinkKeywords
143 } PDF_LINK_KEYWORD;
144 
145 enum {
146   k_author = 0,
147   k_title,
148   k_subject,
149   k_keywords,
150   kNumberOfDocInfoKeywords
151 };
152 
153 
154 /* basic types */
155 #ifdef	USE_MATRICES
156 typedef	double			t_matrix[9];
157 #endif
158 
159 typedef	char		t_tempbuf[512];
160 typedef	unsigned int	PDF_OBJECT_NUM;
161 typedef	PDF_OBJECT_NUM	PDF_PAGE_OBJECT_NUM;  /* an object number that can */
162 					      /* refer ONLY to page object */
163 typedef	unsigned int	PDF_FONT_NUM;
164 typedef	unsigned int	PDF_PAGE_NUM;
165 typedef	unsigned int	PDF_FILE_OFFSET;
166 
167 
168 /* font list */
169 struct t_font_list_entry {
170   struct t_font_list_entry *m_next_font_entry;
171   FULL_CHAR *m_PDF_font_name;
172   FULL_CHAR *m_short_font_name;
173   FULL_CHAR *m_actual_font_name;
174   PDF_OBJECT_NUM m_font_encoding_obj;	/* valid for entire PDF file */
175   PDF_OBJECT_NUM m_pdf_object_number;	/* valid for entire PDF file */
176   BOOLEAN m_font_resource_in_pdf;	/* TRUE when PDF file has       */
177 					/* /Type /Font resource         */
178   BOOLEAN m_in_use;			/* used on a per-page basis */
179 };
180 
181 typedef struct t_font_list_entry t_font_list_entry, *t_font_list_entry_ptr;
182 
183 
184 /* offsets of all objects (for xref list) */
185 typedef	PDF_FILE_OFFSET t_offset_array[kNumberOfObjectsPerBlock];
186 
187 struct t_offset_block {
188   struct t_offset_block *m_next_block;
189   t_offset_array m_block;
190 };
191 
192 typedef struct t_offset_block t_offset_block, *t_offset_block_ptr;
193 
194 
195 /* for /Pages object */
196 typedef PDF_PAGE_OBJECT_NUM t_page_array[kNumberOfPagesPerBlock];
197 
198 struct t_page_block {
199   struct t_page_block *m_next_block;
200   t_page_array m_block;
201 };
202 
203 typedef	struct t_page_block t_page_block, *t_page_block_ptr;
204 
205 
206 /* for font encodings */
207 struct	t_font_encoding_entry {
208   struct t_font_encoding_entry* m_next_entry;
209   PDF_OBJECT_NUM m_object_num;
210   FULL_CHAR *m_font_encoding;
211 };
212 
213 typedef struct t_font_encoding_entry
214   t_font_encoding_entry, *t_font_encoding_entry_ptr;
215 
216 
217 /* for qsave/qrestore [see PDFPage_Push()] */
218 struct t_qsave_entry {
219   struct t_qsave_entry *m_next_entry;
220   int m_page_h_origin, m_page_v_origin;
221   float m_page_h_scale_factor, m_page_v_scale_factor;
222 };
223 
224 typedef struct t_qsave_entry t_qsave_entry, *t_qsave_entry_ptr;
225 
226 
227 /* for qsave/qrestore [see PDFPage_Push()] */
228 struct t_qsave_marking_entry {
229   struct t_qsave_marking_entry* m_next_entry;
230   unsigned int m_buffer_pos;
231 };
232 
233 typedef	struct t_qsave_marking_entry t_qsave_marking_entry, *t_qsave_marking_entry_ptr;
234 
235 
236 /* target of link annotations */
237 struct t_target_annot_entry {
238   struct t_target_annot_entry* m_next_entry;
239 
240   /* all of the following are always defined */
241   FULL_CHAR *m_name;
242   PDF_PAGE_OBJECT_NUM m_page_object_num;
243 
244   /* these are in PDF's default user space coordinates */
245   int m_ll_x;
246   int m_ll_y;
247   int m_ur_x;
248   int m_ur_y;
249 
250   BOOLEAN m_for_export;
251 };
252 
253 typedef struct t_target_annot_entry t_target_annot_entry, *t_target_annot_entry_ptr;
254 
255 /* source of link annotations */
256 struct t_source_annot_entry {
257   struct t_source_annot_entry* m_next_entry;
258 
259   t_target_annot_entry* m_target;	/* if is a link and this is NULL then */
260 					/* the link is a fwd link and remains */
261 					/* unresolvable until the page is     */
262 					/* encountered - instead, the m_name  */
263 					/* field is defined; m_target will be */
264 					/* NULL for URI type links            */
265 
266   FULL_CHAR *m_name;			/* this string is defined if m_target */
267 					/* is NULL otherwise it is null       */
268 					/* for URI links, this contains the   */
269 					/* URI to link to                     */
270   FULL_CHAR *m_file_spec;		/* only defined for link_type ==      */
271 					/* k_link_external                    */
272 
273   /* all of the following are always defined */
274   /* these are in PDF's default user space coordinates */
275   int m_ll_x;
276   int m_ll_y;
277   int m_ur_x;
278   int m_ur_y;
279 
280   PDF_OBJECT_NUM m_this_object_num;	/* obj num of this "/Type /Annot" obj */
281   PDF_PAGE_OBJECT_NUM m_this_page_object_num;	/* obj num of the page that   */
282 					/* this annot lies in                 */
283   PDF_LINK_DEST_OPTION m_dest_option;
284   PDF_LINK_KEYWORD m_link_type;
285 
286   BOOLEAN m_written_to_PDF_file;
287 };
288 
289 typedef struct t_source_annot_entry t_source_annot_entry, *t_source_annot_entry_ptr;
290 
291 
292 /* matrices */
293 #ifdef USE_MATRICES
294 struct t_matrix_entry {
295   struct t_matrix_entry* m_next_entry;
296   t_matrix m_matrix;
297 };
298 
299 typedef struct t_matrix_entry t_matrix_entry, *t_matrix_entry_ptr;
300 #endif
301 
302 
303 /* statics */
304 
305 /* general */
306 static BOOLEAN g_PDF_debug;
307 
308 /* objects */
309 static PDF_OBJECT_NUM		g_next_objnum;
310 static t_offset_block_ptr	g_obj_offset_list;	/* first block       */
311 static t_offset_block_ptr	g_cur_obj_offset_block;
312 
313 /* fonts */
314 static t_font_list_entry_ptr	g_font_list;		/* backwards         */
315 static t_font_encoding_entry_ptr g_font_encoding_list;	/* backwards         */
316 
317 /* pages */
318 static PDF_PAGE_NUM		g_page_count;		/* current page num, */
319 							/* starting at 1     */
320 static PDF_PAGE_OBJECT_NUM	g_page_object_num;	/* obj num of current*/
321 							/* "/Type /Page" obj,*/
322 							/* corr. to page     */
323 							/* num g_page_count  */
324 static t_page_block_ptr		g_page_block_list;	/* first block       */
325 static t_page_block_ptr		g_cur_page_block;
326 static PDF_OBJECT_NUM		g_pages_root;
327 
328 /* document */
329 static int g_doc_h_bound;
330 static int g_doc_v_bound;
331 static FULL_CHAR* g_doc_author;
332 static FULL_CHAR* g_doc_title;
333 static FULL_CHAR* g_doc_subject;
334 static FULL_CHAR* g_doc_keywords;
335 
336 /* link annotations */
337 static t_target_annot_entry_ptr g_target_annot_list;
338 static BOOLEAN g_has_exported_targets;
339 
340 /* globals for each page */
341 /* these indicate what kind of content the page has */
342 static BOOLEAN g_page_uses_fonts;
343 static BOOLEAN g_page_has_text;
344 static BOOLEAN g_page_has_graphics;
345 
346 /* these are only defined when the page has some content */
347 static PDF_OBJECT_NUM g_page_contents_obj_num;
348 static PDF_OBJECT_NUM g_page_length_obj_num;
349 static PDF_FILE_OFFSET g_page_start_offset;
350 
351 /* valid after a PDF_Push and PDF_Pop */
352 static t_qsave_entry_ptr g_qsave_stack;
353 
354 static t_qsave_marking_entry_ptr g_qsave_marking_stack;	/* implemented as a   */
355 							/* linked list; pts   */
356 							/* to top of stack    */
357 static BOOLEAN g_in_buffering_mode;
358 static char g_buffer[kBufferSize];			/* this buffer is used*/
359 							/* for removing redundant operations */
360 static unsigned int g_buffer_pos;
361 
362 /* valid after a link annotation has been defined */
363 static t_source_annot_entry_ptr g_source_annot_list;
364 
365 #ifdef USE_MATRICES
366 static t_matrix g_cur_matrix;
367 static t_matrix_entry_ptr g_matrix_stack;
368 #endif
369 
370 /* track these values in case they are ever required */
371 static float g_page_h_scale_factor, g_page_v_scale_factor;
372 static int g_page_h_origin, g_page_v_origin;
373 static int g_page_line_width;
374 
375 /* magic keywords (actually they will appear in Lout documents as "__in", "__cm", etc.) */
376 static char *g_unit_keywords[kNumberOfUnitKeywords] =
377 {
378   "in", "cm", "pt", "em", "loutf", "loutv", "louts"	/* MUST be followed by a fp number */
379 };
380 
381 static char *g_graphic_keywords[kNumberOfGraphicsKeywords] =
382 {
383   "xsize", "ysize", "xmark", "ymark"	/* like macros, these expand to the actual value */
384 };
385 
386 static char *g_arithmetic_keywords[kNumberOfArithmeticKeywords] =
387 {
388   /* syntax: "__mul(x, y)" emits (x * y) to 2 decimal places              */
389   /*                                                                      */
390   /* Notes:                                                               */
391   /*                                                                      */
392   /*    sin and cos expect their arguments in degrees                     */
393   /*                                                                      */
394   /*    for negation, use "__sub(0, arg)"                                 */
395   /*                                                                      */
396   /*    __pick(i, expr1, expr2, expr3...) picks the ith expr from the     */
397   /*    list of expr the "," are optional (if they are not used, you      */
398   /*    should separate values with whitespace)                           */
399 
400   "add", "sub", "mul", "div", "sin", "cos", "pick"	/* like macros, these expand to the actual value */
401 };
402 
403 static char *g_link_keywords[kNumberOfLinkKeywords] =
404 {
405   /* syntax: "__link_source=<<name_of_target_link [dest_link_option]>>"   */
406   /*                                                                      */
407   /* example: "__link_source=<<chapter6>>"                                */
408   /* example: "__link_source=<<part7 __FitH>>"                            */
409 
410   "link_source=<<",
411 
412   /* syntax: "__link_external=<<name_of_target_link __link_to=file_spec>>"*/
413   /* syntax: "__link_external=<<name_of_target_link __link_to=<< /FS /URL /F (url)>>>>" */
414   /*                                                                      */
415   /* **	note the special format required for URL links **                 */
416   /*                                                                      */
417   /* example: "__link_external=<<chapter6 __link_to=/usr/bin/file.pdf>>"  */
418   /* example: "__link_external=<<chapter6 __link_to=<< /FS /URL /F        */
419   /*          (ftp://ftp.cs.usyd.edu.au/jeff/lout/user.pdf) >>>>"         */
420 
421   "link_external=<<",
422 
423   /* syntax: "__link_URI=<<URL>>"                                         */
424   /*                                                                      */
425   /* example: "__link_URI=<<http://www.adobe.com>>"                       */
426 
427   "link_URI=<<",
428 
429   /* syntax: "__link_target=<<name_of_target_link>>" where                */
430   /* name_of_target_link is in this PDF file; name_of_target_link CANNOT  */
431   /* be accessed by external documents in links                           */
432   /*                                                                      */
433   /* example: "__link_target=<<my_internal_target>>"                      */
434 
435   "link_target=<<",
436 
437   /* syntax: "__link_target_for_export=<<name_of_target_link>>" where     */
438   /* name_of_target_link is in this file; name_of_target_link can be      */
439   /* accessed by external documents in links                              */
440   /*                                                                      */
441   /* example: "__link_target_for_export=<<my_exported_target>>"           */
442 
443   "link_target_for_export=<<"
444 };
445 
446 static char *g_dest_link_options[kNumberOfDestLinkOptions] =
447 {
448   /* see PDF_LINK_DEST_OPTION for descriptions of the meanings of these */
449   "__FitNoChange",
450   "__Fit",
451   "__FitH",
452   "__FitV",
453   "__FitR",
454   "__FitB",
455   "__FitBH",
456   "__FitBV"
457 };
458 
459 static char* g_external_file_spec_keyword[1] =
460 {
461   "__link_to="
462 };
463 
464 static char* g_doc_info_keywords[kNumberOfDocInfoKeywords] =
465 {
466   "author=", "title=", "subject=", "keywords="
467 };
468 
469 static int g_units[kNumberOfUnitKeywords];
470 
471 static int g_graphics_vars[kNumberOfGraphicsKeywords];
472 
473 /* text state */
474 static BOOLEAN g_TJ_pending;
475 static BOOLEAN g_ET_pending;
476 static BOOLEAN g_valid_text_matrix;	/* true when BT...ET block open */
477 
478 
479 /* expressions */
480 static int g_expr_depth = 0;
481 static int g_expr_index;
482 static t_tempbuf g_expr;
483 
484 /* links */
485 static int g_link_depth = 0;
486 static int g_link_index;
487 static t_tempbuf g_link;
488 static PDF_LINK_KEYWORD g_link_keyword;
489 
490 /* the 14 base fonts */
491 static char *g_standard_base_14_fonts[kBase14FontCount] = {
492   "Courier",
493   "Courier-Bold",
494   "Courier-Oblique",
495   "Courier-BoldOblique",
496   "Helvetica",
497   "Helvetica-Bold",
498   "Helvetica-Oblique",
499   "Helvetica-BoldOblique",
500   "Symbol",
501   "Times",
502   "Times-Bold",
503   "Times-Italic",
504   "Times-BoldItalic",
505   "ZapfDingbats"
506 };
507 
508 
509 #if PDF_COMPRESSION
510 static BOOLEAN		g_apply_compression;
511 static z_stream		g_comp_stream;           /* zlib compression stream */
512 static unsigned char*	g_raw_buffer_ptr;
513 
514 /* compression buffers */
515 static unsigned char	g_raw_output[kRawOutputBufferSize];
516 static unsigned char	g_compressed_output[kCompressedOutputBufferSize];
517 #endif
518 
519 /* for calculating largest page object */
520 #ifdef _CALC_LARGEST_PAGE_OBJECT_
521 static PDF_FILE_OFFSET g_max_page_length = 0;
522 #endif
523 
PDFHasValidTextMatrix(void)524 BOOLEAN PDFHasValidTextMatrix(void)	/* this is called from z24.c */
525 {
526   return g_valid_text_matrix;
527 }
528 
529 
530 /*****************************************************************************/
531 /*                                                                           */
532 /*  t_offset_block_ptr  PDFObject_FindOffsetBlock(PDF_OBJECT_NUM in_obj_num) */
533 /*                                                                           */
534 /*  Find the offset block for the given object number.                       */
535 /*                                                                           */
536 /*****************************************************************************/
537 
PDFObject_FindOffsetBlock(PDF_OBJECT_NUM in_obj_num,unsigned int * out_block_pos)538 static t_offset_block_ptr PDFObject_FindOffsetBlock(PDF_OBJECT_NUM in_obj_num,
539   unsigned int* out_block_pos)
540 {
541   int wanted_block_num = (in_obj_num - 1) / kNumberOfObjectsPerBlock;
542   int block_pos = (in_obj_num - 1) % kNumberOfObjectsPerBlock;
543   t_offset_block_ptr the_block = g_obj_offset_list;
544 
545   Assert((in_obj_num > 0) && (in_obj_num < g_next_objnum), no_fpos);
546 
547   /* find block */
548   while (wanted_block_num != 0) {
549     Assert(the_block != NULL, no_fpos);
550     the_block = the_block->m_next_block;
551     wanted_block_num--;
552   }
553   Assert(the_block != NULL, no_fpos);
554 
555   if (out_block_pos != NULL)
556     *out_block_pos = block_pos;
557   return the_block;
558 }
559 
560 
561 /*****************************************************************************/
562 /*                                                                           */
563 /*  PDF_OBJECT_NUM PDFObject_New(FILE* in_fp)                                */
564 /*                                                                           */
565 /*  Return the next available object number.                                 */
566 /*                                                                           */
567 /*****************************************************************************/
568 
PDFObject_New()569 static PDF_OBJECT_NUM PDFObject_New(/* FILE* in_fp */)
570 {
571   int wanted_block_num = (g_next_objnum - 1) / kNumberOfObjectsPerBlock;
572   int block_pos = (g_next_objnum - 1) % kNumberOfObjectsPerBlock;
573   t_offset_block_ptr the_block = g_cur_obj_offset_block;
574 
575   /* if first obj in a block then allocate the block */
576   if (block_pos == 0)
577   {
578     the_block = (t_offset_block_ptr) malloc(sizeof(t_offset_block));
579     if (the_block == NULL)
580       Error(48, 1, "PDFObject_New: run out of memory", FATAL, no_fpos);
581     if (wanted_block_num == 0)  /* if first block in file */
582     {
583       Assert(g_obj_offset_list == NULL, no_fpos);
584       g_obj_offset_list = the_block;
585     }
586     else
587     {
588       Assert(g_cur_obj_offset_block != NULL, no_fpos);
589       g_cur_obj_offset_block->m_next_block = the_block;
590     }
591     the_block->m_next_block = NULL;	/* don't forget to init this! */
592     g_cur_obj_offset_block = the_block;
593   }
594   else
595   {
596     Assert(the_block != NULL, no_fpos);
597   }
598 
599   /* initialise the offset of this object to zero (it hasn't been written    */
600   /* to the PDF file yet)                                                    */
601   the_block->m_block[block_pos] = 0;                  /* ftell(in_fp);       */
602 
603   return g_next_objnum++;
604 }
605 
606 
607 /*****************************************************************************/
608 /*                                                                           */
609 /*  void PDFObject_WriteRef(FILE* in_fp, PDF_OBJECT_NUM in_object_number)    */
610 /*                                                                           */
611 /*  Return the next available object number and write a reference to it.     */
612 /*                                                                           */
613 /*****************************************************************************/
614 
PDFObject_WriteRef(FILE * in_fp,PDF_OBJECT_NUM in_object_number)615 static void PDFObject_WriteRef(FILE* in_fp, PDF_OBJECT_NUM in_object_number)
616 {
617   fprintf(in_fp, "%u 0 R", in_object_number);
618 }
619 
620 
621 /*****************************************************************************/
622 /*                                                                           */
623 /*  void PDFObject_WriteObj(FILE* in_fp, PDF_OBJECT_NUM in_object_number)    */
624 /*                                                                           */
625 /*  Write the object's definition (and remember its file position).          */
626 /*                                                                           */
627 /*****************************************************************************/
628 
PDFObject_WriteObj(FILE * in_fp,PDF_OBJECT_NUM in_object_number)629 static void PDFObject_WriteObj(FILE* in_fp, PDF_OBJECT_NUM in_object_number)
630 {
631   unsigned int block_pos;
632   t_offset_block_ptr block =
633     PDFObject_FindOffsetBlock(in_object_number, &block_pos);
634   Assert(block->m_block[block_pos]==0, no_fpos); /* offset shd be "unknown"  */
635   block->m_block[block_pos] = ftell(in_fp);	 /* remember offset for xref */
636 
637   fprintf(in_fp, "%u 0 obj\n", in_object_number);
638 }
639 
640 /*****************************************************************************/
641 /*                                                                           */
642 /*  PDF_OBJECT_NUM PDFObject_WriteNewObj(FILE* in_fp)                        */
643 /*                                                                           */
644 /*  Return the next available object number and write its definition.        */
645 /*                                                                           */
646 /*****************************************************************************/
647 
PDFObject_WriteNewObj(FILE * in_fp)648 static PDF_OBJECT_NUM PDFObject_WriteNewObj(FILE* in_fp)
649 {
650   PDF_OBJECT_NUM next_ref = PDFObject_New(/* in_fp */);
651   PDFObject_WriteObj(in_fp, next_ref);
652   return next_ref;
653 }
654 
655 
656 /*****************************************************************************/
657 /*                                                                           */
658 /*  PDF_OBJECT_NUM PDFObject_WriteNextRef(FILE* in_fp)                       */
659 /*                                                                           */
660 /*  Return the next available object number and write a reference to it.     */
661 /*                                                                           */
662 /*****************************************************************************/
663 
664 /* ***
665 static PDF_OBJECT_NUM PDFObject_WriteNextRef(FILE* in_fp)
666 {
667   PDF_OBJECT_NUM next_ref = PDFObject_New(in_fp);
668   PDFObject_WriteRef(in_fp, next_ref);
669   return next_ref;
670 }
671 *** */
672 
673 
674 /*****************************************************************************/
675 /*                                                                           */
676 /* void PDFFile_BeginFontEncoding(FILE* in_fp, const char* in_encoding_name) */
677 /*                                                                           */
678 /*  Begin font encoding.                                                     */
679 /*                                                                           */
680 /*****************************************************************************/
681 
PDFFile_BeginFontEncoding(FILE * in_fp,const char * in_encoding_name)682 void PDFFile_BeginFontEncoding(FILE* in_fp, const char* in_encoding_name)
683 {
684   PDF_OBJECT_NUM encoding_num;
685   t_font_encoding_entry_ptr encoding_entry;
686 
687   /* TO FILL IN: create entry in font-encoding list and add this encoding    */
688   if (g_PDF_debug)
689     fprintf(in_fp, "%%\n%% font encoding '%s':\n%%\n", in_encoding_name);
690 
691   encoding_num = PDFObject_WriteNewObj(in_fp);
692   fputs("<<\n/Type /Encoding\n/Differences [ 0\n", in_fp);
693 
694   /* add font encoding to list of encodings (assume we don't get passed the  */
695   /* same encoding more than once)                                           */
696   encoding_entry =
697     (t_font_encoding_entry_ptr) malloc(sizeof(t_font_encoding_entry));
698   if (encoding_entry == NULL)
699     Error(48, 2, "PDFFile_BeginFontEncoding: run out of memory",FATAL,no_fpos);
700 
701   encoding_entry->m_font_encoding =
702     (FULL_CHAR*) malloc(strlen(in_encoding_name) + 1);
703   if (encoding_entry->m_font_encoding == NULL)
704     Error(48, 3, "PDFFile_BeginFontEncoding: out of memory", FATAL, no_fpos);
705 
706   encoding_entry->m_next_entry = g_font_encoding_list;
707   encoding_entry->m_object_num = encoding_num;
708   strcpy((char*) encoding_entry->m_font_encoding, (char*) in_encoding_name);
709   g_font_encoding_list = encoding_entry;
710 }
711 
712 
713 /*****************************************************************************/
714 /*                                                                           */
715 /*  void PDFFile_EndFontEncoding(FILE* in_fp)                                */
716 /*                                                                           */
717 /*  End of font encoding.                                                    */
718 /*                                                                           */
719 /*****************************************************************************/
720 
PDFFile_EndFontEncoding(FILE * in_fp)721 void PDFFile_EndFontEncoding(FILE* in_fp)
722 {
723   fputs("]\n>>\nendobj\n", in_fp);
724 }
725 
726 
727 /*****************************************************************************/
728 /*                                                                           */
729 /* const FULL_CHAR* PDFFont_FindListEntry(const FULL_CHAR* in_real_font_name)*/
730 /*                                                                           */
731 /*  Try to find the font list entry with the specified real font name;       */
732 /*  return the entry's reference if found else return NULL.                  */
733 /*                                                                           */
734 /*****************************************************************************/
735 
736 static t_font_list_entry_ptr
PDFFont_FindListEntry(const FULL_CHAR * in_real_font_name)737   PDFFont_FindListEntry(const FULL_CHAR* in_real_font_name)
738 {
739   t_font_list_entry_ptr entry = g_font_list;
740 
741   while (entry != NULL) {
742     if (strcmp((char*)in_real_font_name, (char*)entry->m_actual_font_name)==0)
743       break;
744     entry = entry->m_next_font_entry;
745   }
746   return entry;
747 }
748 
749 
750 /*****************************************************************************/
751 /*                                                                           */
752 /*  const FULL_CHAR*                                                         */
753 /*    PDFFont_FindListEntry_Short(const FULL_CHAR* in_short_font_name)       */
754 /*                                                                           */
755 /*  Try to find the font list entry with the specified real font name;       */
756 /*  return the entry's reference if found else return NULL.                  */
757 /*                                                                           */
758 /*****************************************************************************/
759 
760 static t_font_list_entry_ptr
PDFFont_FindListEntry_Short(const FULL_CHAR * in_short_font_name)761   PDFFont_FindListEntry_Short(const FULL_CHAR* in_short_font_name)
762 {
763   t_font_list_entry_ptr entry = g_font_list;
764 
765   while (entry != NULL) {
766     if (strcmp((char*)in_short_font_name, (char*)entry->m_short_font_name)==0)
767       break;
768     entry = entry->m_next_font_entry;
769   }
770   return entry;
771 }
772 
773 
774 /*****************************************************************************/
775 /*                                                                           */
776 /*  const t_font_list_entry_ptr PDFFont_NewListEntry(                        */
777 /*   const FULL_CHAR* in_short_font_name, const FULL_CHAR* in_real_font_name)*/
778 /*                                                                           */
779 /*  Create a new font entry and return the short name of the font.           */
780 /*                                                                           */
781 /*****************************************************************************/
782 
783 static t_font_list_entry_ptr
PDFFont_NewListEntry(const FULL_CHAR * in_short_font_name,const FULL_CHAR * in_real_font_name,PDF_OBJECT_NUM in_font_encoding_obj)784   PDFFont_NewListEntry(const FULL_CHAR* in_short_font_name,
785 			const FULL_CHAR* in_real_font_name,
786 			PDF_OBJECT_NUM in_font_encoding_obj)
787 {
788   PDF_FONT_NUM next_font_num = 0;
789   t_font_list_entry_ptr new_entry = g_font_list;
790   /* t_font_list_entry_ptr last_font_list_entry = NULL; */
791 
792   /* find next available font number */
793   {
794     while (new_entry != NULL) {
795       next_font_num++;
796       new_entry = new_entry->m_next_font_entry;
797     }
798   }
799 
800   /* make a new font list entry */
801   {
802     char PDF_font_name[64] = "/F";
803     char num[32];
804 
805     new_entry = (t_font_list_entry_ptr) malloc(sizeof(t_font_list_entry));
806     if (new_entry == NULL)
807       Error(48, 4, "PDFFont_NewListEntry: run out of memory", FATAL, no_fpos);
808 
809     sprintf(num, "%u", next_font_num);
810     strcat(PDF_font_name, num);
811 
812     new_entry->m_PDF_font_name =
813       (FULL_CHAR*) malloc(strlen((char*) PDF_font_name) + 1);
814     if (new_entry->m_PDF_font_name == NULL)
815       Error(48, 5, "PDFFont_NewListEntry: run out of memory", FATAL, no_fpos);
816     strcpy((char*) new_entry->m_PDF_font_name, PDF_font_name);
817 
818     new_entry->m_short_font_name =
819       (FULL_CHAR*) malloc(strlen((char*) in_short_font_name) + 1);
820     if (new_entry->m_short_font_name == NULL)
821       Error(48, 6, "PDFFont_NewListEntry: run out of memory", FATAL, no_fpos);
822     strcpy((char*) new_entry->m_short_font_name, (char*) in_short_font_name);
823 
824     new_entry->m_actual_font_name =
825       (FULL_CHAR*) malloc(strlen((char*) in_real_font_name) + 1);
826     if (new_entry->m_actual_font_name == NULL)
827       Error(48, 7, "PDFFont_NewListEntry: run out of memory", FATAL, no_fpos);
828     strcpy((char*) new_entry->m_actual_font_name, (char*) in_real_font_name);
829 
830     new_entry->m_font_encoding_obj = in_font_encoding_obj;
831 
832     new_entry->m_pdf_object_number = 0;	/* don't give this font resource an  */
833 					/* object number until needed        */
834     /* new_entry->m_in_use = TRUE; */	/* should be cleared after each page */
835     /* g_page_uses_fonts = TRUE;   */
836     new_entry->m_font_resource_in_pdf = FALSE;	/* not in PDF file yet       */
837 
838     new_entry->m_next_font_entry = g_font_list;
839     g_font_list = new_entry;
840   }
841   debug1(DPD, D, "new PDF font entry with short name %s",
842     new_entry->m_short_font_name);
843   return new_entry;
844 }
845 
846 
847 /*****************************************************************************/
848 /*                                                                           */
849 /*  const t_font_list_entry_ptr PDFGetFont(const char* in_real_font_name)    */
850 /*                                                                           */
851 /*  Return the reference of a font entry. Never returns NULL.                */
852 /*                                                                           */
853 /*****************************************************************************/
854 /*
855 static t_font_list_entry_ptr PDFGetFont(const FULL_CHAR* in_real_font_name)
856 {
857   t_font_list_entry_ptr entry = PDFFont_FindListEntry(in_real_font_name);
858   if (entry == NULL)
859     entry = PDFFont_NewListEntry(in_real_font_name);
860   return entry;
861 }
862 */
863 
864 /*****************************************************************************/
865 /*                                                                           */
866 /*  PDFFont_WriteObjectRef(FILE* in_fp, t_font_list_entry_ptr in_font_entry) */
867 /*                                                                           */
868 /*  Write a reference to the object to the file.                             */
869 /*                                                                           */
870 /*****************************************************************************/
871 
PDFFont_WriteObjectRef(FILE * in_fp,const t_font_list_entry * in_font_entry)872 static void PDFFont_WriteObjectRef(FILE* in_fp,
873   const t_font_list_entry* in_font_entry)
874 {
875   Assert(in_font_entry->m_pdf_object_number != 0, no_fpos);
876   PDFObject_WriteRef(in_fp, in_font_entry->m_pdf_object_number);
877 }
878 
879 
880 /*****************************************************************************/
881 /*                                                                           */
882 /*  void PDFFont_WriteObject(FILE* in_fp,                                    */
883 /*    t_font_list_entry_ptr in_font_entry)                                   */
884 /*                                                                           */
885 /*  Write a reference to the object to the file.                             */
886 /*                                                                           */
887 /*****************************************************************************/
888 
PDFFont_WriteObject(FILE * in_fp,t_font_list_entry_ptr in_font_entry)889 static void PDFFont_WriteObject(FILE* in_fp, t_font_list_entry_ptr in_font_entry)
890 {
891   if (in_font_entry->m_pdf_object_number == 0)
892     in_font_entry->m_pdf_object_number = PDFObject_New(/* in_fp */);
893   PDFObject_WriteObj(in_fp, in_font_entry->m_pdf_object_number);
894 }
895 
896 
897 /*****************************************************************************/
898 /*                                                                           */
899 /*  BOOLEAN PDFFont_IsOneOfTheBase14Fonts(const FULL_CHAR* in_real_font_name)*/
900 /*                                                                           */
901 /*  Returns true if given font is one of the base 14 fonts.                  */
902 /*                                                                           */
903 /*****************************************************************************/
904 
PDFFont_IsOneOfTheBase14Fonts(const FULL_CHAR * in_real_font_name)905 static BOOLEAN PDFFont_IsOneOfTheBase14Fonts(const FULL_CHAR* in_real_font_name)
906 {
907   int i;
908   for (i = 0; i < kBase14FontCount; i++)
909     if (strcmp(g_standard_base_14_fonts[i], (char*) in_real_font_name) == 0)
910       return TRUE;
911   return FALSE;
912 }
913 
914 
915 /*****************************************************************************/
916 /*                                                                           */
917 /*  PDFFont_WriteFontResource(FILE* in_fp,                                   */
918 /*    t_font_list_entry_ptr in_font_entry)                                   */
919 /*                                                                           */
920 /*  Writes out the PDF idea of a Font resource.                              */
921 /*                                                                           */
922 /*****************************************************************************/
923 
PDFFont_WriteFontResource(FILE * in_fp,t_font_list_entry_ptr in_font_entry)924 static void PDFFont_WriteFontResource(FILE* in_fp,
925   t_font_list_entry_ptr in_font_entry)
926 {
927   if (! in_font_entry->m_font_resource_in_pdf)
928   {
929     in_font_entry->m_font_resource_in_pdf = TRUE;
930 
931     if (g_PDF_debug)
932       fprintf(in_fp, "%%\n%% declare use of font %s:\n%%\n",
933 	in_font_entry->m_actual_font_name);
934 
935     PDFFont_WriteObject(in_fp, in_font_entry);
936     fputs("<<\n/Type /Font\n/Subtype /Type1\n", in_fp);
937     fprintf(in_fp, "/Name %s\n", (char*) in_font_entry->m_PDF_font_name);
938     fprintf(in_fp, "/BaseFont /%s\n", (char*) in_font_entry->m_actual_font_name);
939     if (! PDFFont_IsOneOfTheBase14Fonts(in_font_entry->m_actual_font_name))
940     {
941       /* ***
942       fputs("/FirstChar 0"\n, in_fp);	- we don't do first chars (yet)
943       fputs("/LastChar 255\n", in_fp);	- we don't do last chars (yet)
944       fputs("/Widths ", in_fp);		- we don't do last chars (yet)
945       fputs("/FontDescriptor ", in_fp);	- we don't do font descriptors (yet)
946       *** */
947     }
948 
949     if (in_font_entry->m_font_encoding_obj != 0)
950     {
951       fputs("/Encoding ", in_fp);
952       PDFObject_WriteRef(in_fp, in_font_entry->m_font_encoding_obj);
953       fputs("\n", in_fp);
954     }
955 
956     /* ***
957     else
958       Error(48, 8, "PDFFont_WriteFontResource: a font has no encoding",
959 	WARN, no_fpos);
960     *** */
961     fputs(">>\nendobj\n", in_fp);
962   }
963 }
964 
965 
966 /*****************************************************************************/
967 /*                                                                           */
968 /*  PDFFont_WriteFontResource_name(FILE* in_fp,                              */
969 /*    const FULL_CHAR* in_real_font_name)                                    */
970 /*                                                                           */
971 /*  Writes out the PDF idea of a Font resource.                              */
972 /*                                                                           */
973 /*****************************************************************************/
974 
975 /* ***
976 static void PDFFont_WriteFontResource_name(FILE* in_fp,
977   const FULL_CHAR* in_real_font_name)
978 {
979   t_font_list_entry_ptr entry = PDFFont_FindListEntry(in_real_font_name);
980   Assert(entry != NULL, no_fpos);
981   PDFFont_WriteFontResource(in_fp, entry);
982 }
983 *** */
984 
985 
986 /*****************************************************************************/
987 /*                                                                           */
988 /*  const FULL_CHAR* PDFGetPDFFontName(const FULL_CHAR* in_real_font_name)   */
989 /*                                                                           */
990 /*  Return the short name of a font.                                         */
991 /*                                                                           */
992 /*****************************************************************************/
993 
994 /* ***
995 static const FULL_CHAR* PDFGetPDFFontName(const FULL_CHAR* in_real_font_name)
996 {
997   t_font_list_entry_ptr entry = PDFFont_FindListEntry(in_real_font_name);
998   Assert(entry != NULL, no_fpos);
999   return entry->m_PDF_font_name;
1000 }
1001 *** */
1002 
1003 
1004 /*****************************************************************************/
1005 /*                                                                           */
1006 /* PDF_OBJECT_NUM PDFFont_FindFontEncoding(FULL_CHAR* in_font_encoding_name) */
1007 /*                                                                           */
1008 /*  Return the object number of a given font encoding.                       */
1009 /*                                                                           */
1010 /*****************************************************************************/
1011 
PDFFont_FindFontEncoding(const FULL_CHAR * in_font_encoding_name)1012 static PDF_OBJECT_NUM PDFFont_FindFontEncoding(
1013   const FULL_CHAR* in_font_encoding_name)
1014 {
1015   t_font_encoding_entry_ptr entry = g_font_encoding_list;
1016 
1017   /* these two lines are Uwe patch Jul 18, 2000 */
1018   if (in_font_encoding_name == NULL)
1019     return 0;
1020 
1021   while (entry != NULL)
1022   {
1023     if (strcmp((char*)in_font_encoding_name, (char*)entry->m_font_encoding)==0)
1024       break;
1025     entry = entry->m_next_entry;
1026   }
1027   return (entry != NULL) ? entry->m_object_num : 0;
1028 }
1029 
1030 
1031 /*****************************************************************************/
1032 /*                                                                           */
1033 /*  void PDFFont_AddFont(                                                    */
1034 /*           FILE* in_fp, const FULL_CHAR* in_short_font_name,               */
1035 /*           const FULL_CHAR* in_real_font_name)                             */
1036 /*                                                                           */
1037 /*  Add this font to the list of fonts that the document uses. Also remember */
1038 /*  that this font is "in use" (output when page resources are written).     */
1039 /*                                                                           */
1040 /*****************************************************************************/
1041 
PDFFont_AddFont(FILE * in_fp,const FULL_CHAR * in_short_font_name,const FULL_CHAR * in_real_font_name,const FULL_CHAR * in_font_encoding_name)1042 void PDFFont_AddFont(FILE* in_fp, const FULL_CHAR* in_short_font_name,
1043   const FULL_CHAR* in_real_font_name, const FULL_CHAR* in_font_encoding_name)
1044 {
1045   t_font_list_entry_ptr entry = PDFFont_FindListEntry(in_real_font_name);
1046   debug4(DPD, D, "PDFFont_AddFont(-, %s, %s, %s) [new = %s]",
1047     in_short_font_name, in_real_font_name,
1048     (in_font_encoding_name != (FULL_CHAR *) NULL ? in_font_encoding_name : ""),
1049     bool(entry == NULL));
1050   /* *** this attempted bug fix by Jeff K. problem may be multiple font
1051 	 entries for the same font
1052   if (entry == NULL)
1053   *** */
1054   if (TRUE)
1055     entry = PDFFont_NewListEntry(in_short_font_name, in_real_font_name,
1056       PDFFont_FindFontEncoding(in_font_encoding_name));
1057 
1058   /* ***
1059   entry->m_in_use = TRUE;
1060   g_page_uses_fonts = TRUE;
1061   *** */
1062 }
1063 
1064 
1065 /*****************************************************************************/
1066 /*                                                                           */
1067 /*  void PDFPage_SetVars(int xsize, int ysize, int xmark, int ymark,         */
1068 /*    int loutf, int loutv, int louts)                                       */
1069 /*                                                                           */
1070 /*  Writes a string to the page's stream.                                    */
1071 /*                                                                           */
1072 /*****************************************************************************/
1073 
PDFPage_SetVars(int xsize,int ysize,int xmark,int ymark,int loutf,int loutv,int louts)1074 void PDFPage_SetVars(int xsize, int ysize, int xmark, int ymark,
1075   int loutf, int loutv, int louts)
1076 {
1077   g_graphics_vars[k_xsize] = xsize;
1078   g_graphics_vars[k_ysize] = ysize;
1079   g_graphics_vars[k_xmark] = xmark;
1080   g_graphics_vars[k_ymark] = ymark;
1081 
1082   g_units[k_loutf] = loutf;
1083   g_units[k_loutv] = loutv;
1084   g_units[k_louts] = louts;
1085 }
1086 
1087 
1088 /*****************************************************************************/
1089 /*                                                                           */
1090 /*  void PDFPage_FlushCompressedBuffer(FILE* in_fp)                          */
1091 /*                                                                           */
1092 /*  Flushes the compressed output buffer to the page's stream.               */
1093 /*                                                                           */
1094 /*****************************************************************************/
1095 
1096 #if PDF_COMPRESSION
PDFPage_FlushCompressedBuffer(FILE * in_fp)1097 static void PDFPage_FlushCompressedBuffer(FILE* in_fp)
1098 {
1099   int err;
1100 
1101   Assert(g_apply_compression, no_fpos);
1102   do {
1103     err = deflate(&g_comp_stream, Z_FINISH);
1104 
1105     fwrite(g_compressed_output,
1106       sizeof(g_compressed_output) - g_comp_stream.avail_out, 1, in_fp);
1107     g_comp_stream.next_out = g_compressed_output;
1108     g_comp_stream.avail_out = sizeof(g_compressed_output);
1109   } while (err == Z_OK);
1110 
1111   if (err != Z_STREAM_END)
1112     Error(48, 9, "PDFPage_FlushCompressedBuffer: zlib error occurred",
1113       FATAL, no_fpos);
1114 
1115   err = deflateEnd(&g_comp_stream);
1116   if (err != Z_OK)
1117     Error(48, 10, "PDFPage_FlushCompressedBuffer: zlib error occurred",
1118       FATAL, no_fpos);
1119 }
1120 
1121 
1122 /*****************************************************************************/
1123 /*                                                                           */
1124 /*  void PDFPage_FlushRawBuffer(FILE* in_fp)                                 */
1125 /*                                                                           */
1126 /*  Attempts to compress the raw buffer; also flushes the compressed output  */
1127 /*  buffer to the page's stream if it is full.                               */
1128 /*                                                                           */
1129 /*****************************************************************************/
1130 
PDFPage_FlushRawBuffer(FILE * in_fp)1131 static void PDFPage_FlushRawBuffer(FILE* in_fp)
1132 {
1133   int err;
1134 
1135   /* compress the raw buffer */
1136   Assert(g_apply_compression, no_fpos);
1137   g_comp_stream.next_in = g_raw_output;
1138   g_comp_stream.avail_in = (uInt) (g_raw_buffer_ptr - g_raw_output);
1139   Assert(g_comp_stream.avail_out != 0, no_fpos);
1140 
1141   /* always compress to the point where the raw buffer is empty */
1142   do {
1143     err = deflate(&g_comp_stream, Z_NO_FLUSH);
1144     /* bug fix from newman-andy@yale.edu Feb 23 2000 if (err != Z_OK) */
1145     if ( err != Z_OK && g_comp_stream.avail_in != 0 )
1146       Error(48, 11, "PDFPage_FlushRawBuffer: zlib error occurred",FATAL,no_fpos);
1147 
1148     /* IF compressed output buffer is full THEN flush it to disk and reset it */
1149     if (g_comp_stream.avail_out == 0)
1150     {
1151       if (fwrite(g_compressed_output, sizeof(g_compressed_output), 1, in_fp)!=1)
1152 	Error(48, 12, "PDFPage_FlushRawBuffer: write error occurred",
1153 	  FATAL, no_fpos);
1154       g_comp_stream.next_out = g_compressed_output;
1155       g_comp_stream.avail_out = sizeof(g_compressed_output);
1156     }
1157   } while (g_comp_stream.avail_in != 0);
1158 
1159   /* reset raw buffer for next call */
1160   g_raw_buffer_ptr = g_raw_output;
1161 }
1162 #endif
1163 
1164 
1165 /*****************************************************************************/
1166 /*                                                                           */
1167 /*  void PDFPage_WriteStream(FILE* in_fp, char* in_str)                      */
1168 /*                                                                           */
1169 /*  Writes a string to the page's stream.                                    */
1170 /*                                                                           */
1171 /*****************************************************************************/
1172 
PDFPage_WriteStream(FILE * in_fp,char * in_str)1173 static void PDFPage_WriteStream(FILE* in_fp, char* in_str)
1174 {
1175   if (*in_str == 0)
1176     return;
1177 
1178 #if PDF_COMPRESSION
1179   if (g_apply_compression)
1180   {
1181     unsigned int total = strlen(in_str);
1182     char *ptr = in_str;
1183 
1184     while (total != 0)
1185     {
1186       unsigned int len = total;
1187       BOOLEAN needToFlush =
1188 	((g_raw_buffer_ptr + len) > (g_raw_output + sizeof(g_raw_output)));
1189       if (needToFlush)
1190 	len = g_raw_output + sizeof(g_raw_output) - g_raw_buffer_ptr;
1191       memcpy(g_raw_buffer_ptr, ptr, len);
1192 
1193       ptr += len;
1194       g_raw_buffer_ptr += len;
1195       total -= len;
1196 
1197       /* IF need to flush raw buffer THEN do so */
1198       if (needToFlush) PDFPage_FlushRawBuffer(in_fp);
1199     } /* while still have bytes to process */
1200   }
1201   else
1202 #endif
1203     fputs(in_str, in_fp);
1204 }
1205 
1206 
1207 /*****************************************************************************/
1208 /*                                                                           */
1209 /*  void PDFPage_Begin(FILE* in_fp)                                          */
1210 /*                                                                           */
1211 /*  Begins the page's stream.                                                */
1212 /*                                                                           */
1213 /*****************************************************************************/
1214 
PDFPage_Begin(FILE * in_fp)1215 static void PDFPage_Begin(FILE* in_fp)
1216 {
1217   if (g_page_contents_obj_num == 0)
1218   {
1219     t_tempbuf str;
1220 
1221     if (g_PDF_debug)
1222       fprintf(in_fp, "%%\n%% page %u's contents:\n%%\n", g_page_count);
1223 
1224     g_page_contents_obj_num = PDFObject_WriteNewObj(in_fp);
1225     g_page_length_obj_num = PDFObject_New(/* in_fp */);
1226     fputs("<< /Length ", in_fp);
1227     PDFObject_WriteRef(in_fp, g_page_length_obj_num);
1228 #if PDF_COMPRESSION
1229     if (g_apply_compression) fputs(" /Filter /FlateDecode", in_fp);
1230 #endif
1231     fputs(" >>\nstream\n", in_fp);
1232     g_page_start_offset = ftell(in_fp);
1233 
1234 #if PDF_COMPRESSION
1235     if (g_apply_compression)
1236     {
1237       int err;
1238 
1239       g_raw_buffer_ptr = g_raw_output;
1240       g_comp_stream.zalloc = (alloc_func) Z_NULL;
1241       g_comp_stream.zfree = (free_func) Z_NULL;
1242       g_comp_stream.opaque = (voidpf) Z_NULL;
1243 
1244       err = deflateInit(&g_comp_stream, Z_DEFAULT_COMPRESSION);
1245       if (err != Z_OK)
1246 	Error(48, 13, "PDFPage_Begin: zlib error occurred", FATAL, no_fpos);
1247 
1248       g_comp_stream.next_out = g_compressed_output;
1249       g_comp_stream.avail_out = sizeof(g_compressed_output);
1250     }
1251 #endif
1252 
1253 #ifndef USE_MATRICES
1254     sprintf(str, "%.2f 0 0 %.2f 0 0 cm\n",
1255       g_page_h_scale_factor, g_page_v_scale_factor);
1256     PDFPage_WriteStream(in_fp, str);
1257 #endif
1258     sprintf(str, "%u w\n", g_page_line_width);
1259     PDFPage_WriteStream(in_fp, str);
1260   }
1261 }
1262 
1263 
1264 /*****************************************************************************/
1265 /*                                                                           */
1266 /*  void PDFPage_FlushBuffer(FILE* in_fp)                                    */
1267 /*                                                                           */
1268 /*  Flush the buffer to the page's stream and turn off buffering mode.       */
1269 /*                                                                           */
1270 /*****************************************************************************/
1271 
PDFPage_FlushBuffer(FILE * in_fp)1272 static void PDFPage_FlushBuffer(FILE* in_fp)
1273 {
1274   if (g_in_buffering_mode)
1275   {
1276     g_in_buffering_mode = FALSE;
1277 
1278     /* empty the stack since it's no longer needed */
1279     while (g_qsave_marking_stack != NULL)
1280     {
1281       t_qsave_marking_entry_ptr entry = g_qsave_marking_stack;
1282       g_qsave_marking_stack = entry->m_next_entry;
1283       free(entry);
1284     }
1285 
1286     /* output the buffer */
1287     PDFPage_WriteStream(in_fp, g_buffer);
1288   }
1289 }
1290 
1291 
1292 /*****************************************************************************/
1293 /*                                                                           */
1294 /*  PDF_FILE_OFFSET PDFPage_End(FILE* in_fp)                                 */
1295 /*                                                                           */
1296 /*  Ends the page's stream.                                                  */
1297 /*                                                                           */
1298 /*****************************************************************************/
1299 
PDFPage_End(FILE * in_fp)1300 static PDF_FILE_OFFSET PDFPage_End(FILE* in_fp)
1301 {
1302 
1303   /* if page has no marks on it then write out an empty stream */
1304   if (g_in_buffering_mode)
1305   {
1306     g_buffer_pos = 0;
1307     g_buffer[0] = '\0';			/* force empty string to be written  */
1308     PDFPage_FlushBuffer(in_fp);	  /* all I really want is to empty the stack */
1309   }
1310 
1311   /* IF applying compression THEN first flush the raw buffer and then flush */
1312   /* the compressed buffer (must be performed in that order!)               */
1313 #if PDF_COMPRESSION
1314   if (g_apply_compression)
1315   {
1316     if ((g_raw_buffer_ptr > g_raw_output) && (g_raw_buffer_ptr[-1] == '\n'))
1317       g_raw_buffer_ptr--;		/* remove last linefeed */
1318 
1319     PDFPage_FlushRawBuffer(in_fp);
1320     PDFPage_FlushCompressedBuffer(in_fp);
1321     fputs("\n", in_fp);
1322   }
1323 #endif
1324 
1325   /* close page's stream */
1326   Assert(g_page_contents_obj_num != 0, no_fpos);
1327   {
1328     PDF_FILE_OFFSET page_length = ftell(in_fp) - g_page_start_offset;
1329 
1330     /* close page's stream */
1331     fputs("endstream\nendobj\n", in_fp);
1332     return page_length;
1333   }
1334   return 0;
1335 }
1336 
1337 
1338 /*****************************************************************************/
1339 /*                                                                           */
1340 /*  void PDFPage_Write(FILE* in_fp, char* in_str)                            */
1341 /*                                                                           */
1342 /*  Writes a string to the page's stream.                                    */
1343 /*                                                                           */
1344 /*****************************************************************************/
1345 
PDFPage_Write(FILE * in_fp,char * in_str)1346 void PDFPage_Write(FILE* in_fp, char* in_str)
1347 {
1348   if (*in_str == 0)
1349     return;
1350 
1351   PDFPage_Begin(in_fp);	/* write page content's hdr "<< /Length >> stream"...*/
1352 
1353   /* IF trying to remove redundant operations THEN */
1354   if (g_in_buffering_mode)
1355   {
1356 
1357     /* if buffer will overflow then turn off buffering and flush buffer */
1358     unsigned int len = strlen(in_str);
1359     if ( (g_buffer_pos + len) > (kBufferSize-1) )	/* -1 for NULL char */
1360     {
1361       PDFPage_FlushBuffer(in_fp);
1362       PDFPage_WriteStream(in_fp, in_str);
1363     }
1364     else
1365     {
1366       strcpy(g_buffer + g_buffer_pos, in_str);		/* save into buffer */
1367       g_buffer_pos += len;
1368     }
1369   }
1370   else
1371   {
1372     if (g_TJ_pending)
1373     {
1374       g_TJ_pending  = FALSE;				/* clear it */
1375       PDFPage_WriteStream(in_fp, ")]TJ\n");
1376     }
1377 
1378     if (g_ET_pending)
1379     {
1380       g_ET_pending  = FALSE;				/* clear it */
1381       PDFPage_WriteStream(in_fp, "ET\n");
1382       g_valid_text_matrix = FALSE;			/* Td is not allowed */
1383     }
1384 
1385     PDFPage_WriteStream(in_fp, in_str);
1386   }
1387 }
1388 
1389 
1390 /*****************************************************************************/
1391 /*                                                                           */
1392 /*  PDFPage_Push(FILE* in_fp)                                                */
1393 /*                                                                           */
1394 /*  Saves the current graphics state.                                        */
1395 /*                                                                           */
1396 /*****************************************************************************/
1397 
PDFPage_Push(FILE * in_fp)1398 void PDFPage_Push(FILE* in_fp)
1399 {
1400 
1401   /* push origin coords */
1402   {
1403     t_qsave_entry_ptr entry = (t_qsave_entry_ptr) malloc(sizeof(t_qsave_entry));
1404     if (entry == NULL)
1405       Error(48, 14, "PDFPage_Push: run out of memory", FATAL, no_fpos);
1406 
1407     entry->m_page_h_origin = g_page_h_origin;
1408     entry->m_page_v_origin = g_page_v_origin;
1409     /* entry->m_page_h_scale_factor = g_page_h_scale_factor; */
1410     /* entry->m_page_v_scale_factor = g_page_v_scale_factor; */
1411     entry->m_next_entry = g_qsave_stack;
1412     g_qsave_stack = entry;
1413   }
1414 
1415   /* if buffering text */
1416   if (g_in_buffering_mode)
1417   {
1418 
1419     /* push current state */
1420     t_qsave_marking_entry_ptr entry =
1421       (t_qsave_marking_entry_ptr) malloc(sizeof(t_qsave_marking_entry));
1422     if (entry == NULL)
1423       Error(48, 15, "PDFPage_Push: run out of memory", FATAL, no_fpos);
1424 
1425     entry->m_next_entry = g_qsave_marking_stack;    /* next-to-top-of-stack */
1426     entry->m_buffer_pos = g_buffer_pos;
1427     g_qsave_marking_stack = entry;		    /* new TOS              */
1428     /* g_in_buffering_mode = TRUE; */
1429   }
1430 
1431   /* write out push op */
1432   PDFPage_Write(in_fp, "q\n");
1433 }
1434 
1435 
1436 /*****************************************************************************/
1437 /*                                                                           */
1438 /*  PDFPage_Pop(FILE* in_fp)                                                 */
1439 /*                                                                           */
1440 /*  Restores the current graphics state.                                     */
1441 /*                                                                           */
1442 /*****************************************************************************/
1443 
PDFPage_Pop(FILE * in_fp)1444 void PDFPage_Pop(FILE* in_fp)
1445 {
1446 
1447   /* pop origin coords */
1448   {
1449     t_qsave_entry_ptr entry = g_qsave_stack;
1450 
1451     g_page_h_origin = entry->m_page_h_origin;
1452     g_page_v_origin = entry->m_page_v_origin;
1453     /* g_page_h_scale_factor = entry->m_page_h_scale_factor; */
1454     /* g_page_v_scale_factor = entry->m_page_v_scale_factor; */
1455 
1456     g_qsave_stack = entry->m_next_entry;
1457 
1458     free(entry);
1459   }
1460 
1461   /* if no marks on page since last push (and thus there should be a stack) */
1462   if (g_in_buffering_mode)
1463   {
1464 
1465     /* pop state: behave as if the q...Q never existed */
1466     t_qsave_marking_entry_ptr entry = g_qsave_marking_stack;
1467 
1468     Assert(entry != NULL, no_fpos);
1469 
1470     g_qsave_marking_stack = entry->m_next_entry;	/* new TOS */
1471     g_buffer_pos   = entry->m_buffer_pos;
1472     g_buffer[g_buffer_pos] = '\0';	/* chop off unwanted text */
1473 
1474     free(entry);
1475   }
1476   else
1477   {
1478     Assert(g_qsave_marking_stack == NULL, no_fpos);
1479     PDFPage_Write(in_fp, "\nQ\n");
1480   }
1481 }
1482 
1483 
1484 /*****************************************************************************/
1485 /*                                                                           */
1486 /*  PDFFont_Set(FILE* in_fp, FULL_LENGTH in_font_size,                       */
1487 /*    FULL_CHAR* in_font_name)                                               */
1488 /*                                                                           */
1489 /*  Sets the font name and size for subsequent text write statements.        */
1490 /*                                                                           */
1491 /*****************************************************************************/
1492 
PDFFont_Set(FILE * in_fp,FULL_LENGTH in_font_size,FULL_CHAR * in_short_font_name)1493 void PDFFont_Set(FILE* in_fp, FULL_LENGTH in_font_size,
1494   FULL_CHAR *in_short_font_name)
1495 {
1496   t_tempbuf str;
1497 
1498   t_font_list_entry_ptr entry = PDFFont_FindListEntry_Short(in_short_font_name);
1499   if( entry == NULL )
1500   {
1501     Error(48, 42, "cannot find font entry for name %s", FATAL, no_fpos,
1502       in_short_font_name);
1503   }
1504   /* Assert(entry != NULL, no_fpos); */
1505 #ifdef USE_MATRICES
1506   sprintf(str, "%s %u Tf\n", entry->m_PDF_font_name,
1507     (int) (g_page_v_scale_factor * in_font_size));
1508 #else
1509   sprintf(str, "%s %u Tf\n", entry->m_PDF_font_name, in_font_size);
1510   /* g_text_font_size_in_ems = g_page_v_scale_factor * in_font_size; */
1511 #endif
1512 
1513 #if 1
1514 
1515   /* font changes can occur within BT...ET blocks, so temporarily turn off   */
1516   /* g_ET_pending. I do it this way so that the qsave_marking_stack          */
1517   /* optimisation can still be applied (this avoids output such as           */
1518   /* "/F0 240 Tf /F0 240 Tf /F1 600 Tf" and instead produces "")             */
1519   if (g_TJ_pending)
1520   {
1521     g_TJ_pending = FALSE;		/* clear it */
1522     PDFPage_WriteStream(in_fp, ")]TJ\n");
1523   }
1524 
1525   {
1526     BOOLEAN cur_ET_pending = g_ET_pending;
1527 
1528     g_ET_pending = FALSE;		/* clear it */
1529     PDFPage_Write(in_fp, str);
1530     g_ET_pending = cur_ET_pending;	/* restore it */
1531   }
1532 #else
1533   /* font changes can occur within BT...ET blocks, so bypass PDFPage_Write() */
1534   PDFPage_WriteStream(in_fp, str);
1535 #endif
1536   entry->m_in_use = TRUE;
1537   g_page_uses_fonts = TRUE;
1538 }
1539 
1540 
1541 /*****************************************************************************/
1542 /*                                                                           */
1543 /*  void PDFText_RMove(FILE* in_fp, int hdelta, int vdelta)                  */
1544 /*                                                                           */
1545 /*  Offsets text pen by the given offsets.                                   */
1546 /*                                                                           */
1547 /*****************************************************************************/
1548 
1549 /* ***
1550 void PDFText_RMove(FILE* in_fp, int hdelta, int vdelta)
1551 {
1552   t_tempbuf str;
1553 
1554   g_tx_hpos += hdelta;
1555   g_tx_vpos += vdelta;
1556 #if 1
1557   sprintf(str, "ET\n1 0 0 1 %d %d cm\nBT\n", hdelta, vdelta);
1558 #else
1559   sprintf(str, "1 0 0 1 %d %d Tm\n", g_tx_hpos, g_tx_vpos);
1560 #endif
1561   PDFPage_Write(in_fp, str);
1562 }
1563 *** */
1564 
1565 
1566 /*****************************************************************************/
1567 /*                                                                           */
1568 /*  void PDFText_MoveTo(FILE* in_fp, int hpos, int vpos)                     */
1569 /*                                                                           */
1570 /*  Move text pen to the given coords.                                       */
1571 /*                                                                           */
1572 /*****************************************************************************/
1573 
1574 /* ***
1575 static void PDFText_MoveTo(FILE* in_fp, int hpos, int vpos)
1576 {
1577   g_tx_hpos = 0;
1578   g_tx_vpos = 0;
1579 #if 1
1580   PDFText_RMove(in_fp, hpos, vpos);
1581 #else
1582   {
1583     t_tempbuf str;
1584     sprintf(str, "1 0 0 1 %d %d Tm\n", hpos, vpos);
1585     PDFPage_Write(in_fp, str);
1586   }
1587 #endif
1588 }
1589 *** */
1590 
1591 
1592 /*****************************************************************************/
1593 /*                                                                           */
1594 /*  void PDFText_OpenString(FILE* in_fp)                                     */
1595 /*                                                                           */
1596 /*  Open TJ block                                                            */
1597 /*                                                                           */
1598 /*****************************************************************************/
1599 
PDFText_OpenString(FILE * in_fp)1600 static void PDFText_OpenString(FILE* in_fp)
1601 {
1602   if (g_TJ_pending)
1603     g_TJ_pending = FALSE;	/* clear it */
1604   else
1605     PDFPage_Write(in_fp, "[(");
1606 }
1607 
1608 
1609 /*****************************************************************************/
1610 /*                                                                           */
1611 /*  void PDFText_MoveToXYAndOpen(FILE* in_fp, int hpos, int vpos)           */
1612 /*                                                                           */
1613 /*  Move text pen to the given coords.                                       */
1614 /*                                                                           */
1615 /*****************************************************************************/
1616 
PDFText_MoveToXYAndOpen(FILE * in_fp,int hpos,int vpos)1617 static void PDFText_MoveToXYAndOpen(FILE* in_fp, int hpos, int vpos)
1618 {
1619 #if 1
1620   t_tempbuf str;
1621   sprintf(str, "1 0 0 1 %d %d Tm\n", hpos, vpos);
1622   PDFPage_Write(in_fp, str);
1623 #else
1624   PDFText_MoveTo(in_fp, hpos, vpos);
1625 #endif
1626   PDFText_OpenString(in_fp);
1627 }
1628 
1629 
1630 /*****************************************************************************/
1631 /*                                                                           */
1632 /*  void PDFText_MoveToXAndOpen(FILE* in_fp, int hpos, int vpos)             */
1633 /*                                                                           */
1634 /*  Move text pen to the given coords.                                       */
1635 /*                                                                           */
1636 /*****************************************************************************/
1637 
PDFText_MoveToXAndOpen(FILE * in_fp,int hpos)1638 static void PDFText_MoveToXAndOpen(FILE* in_fp, int hpos)
1639 {
1640 #if 1
1641   t_tempbuf str;
1642   sprintf(str, "%d 0 Td\n", hpos);
1643   PDFPage_Write(in_fp, str);
1644 #else
1645   PDFText_MoveTo(in_fp, hpos, vpos);
1646 #endif
1647   PDFText_OpenString(in_fp);
1648 }
1649 
1650 
1651 /*****************************************************************************/
1652 /*                                                                           */
1653 /*  void PDFText_OpenBT(FILE* in_fp)                                         */
1654 /*                                                                           */
1655 /*  Opens a text object at the given coords.                                 */
1656 /*                                                                           */
1657 /*****************************************************************************/
1658 
PDFText_OpenBT(FILE * in_fp)1659 static void PDFText_OpenBT(FILE* in_fp)
1660 {
1661   PDFPage_FlushBuffer(in_fp);	/* about to mark page: flush buffered PDF    */
1662 
1663   g_page_has_text = TRUE;
1664 
1665   if (g_TJ_pending)
1666   {
1667     g_TJ_pending = FALSE;		/* clear it */
1668     PDFPage_WriteStream(in_fp, ")]TJ\n");
1669   }
1670 
1671   if (g_ET_pending)
1672     g_ET_pending = FALSE;		/* clear it */
1673   else
1674   {
1675     PDFPage_Write(in_fp, "BT\n");
1676     g_valid_text_matrix = TRUE;		/* Td is allowed */
1677   }
1678 }
1679 
1680 
1681 /*****************************************************************************/
1682 /*                                                                           */
1683 /*  void PDFText_OpenXY(FILE* in_fp, int hpos, int vpos)                     */
1684 /*                                                                           */
1685 /*  Opens a text object at the given coords.                                 */
1686 /*                                                                           */
1687 /*****************************************************************************/
1688 
PDFText_OpenXY(FILE * in_fp,int hpos,int vpos)1689 void PDFText_OpenXY(FILE* in_fp, int hpos, int vpos)
1690 {
1691   PDFText_OpenBT(in_fp);
1692   PDFText_MoveToXYAndOpen(in_fp, hpos, vpos);
1693 }
1694 
1695 
1696 /*****************************************************************************/
1697 /*                                                                           */
1698 /*  void PDFText_OpenX(FILE* in_fp, int hpos)                                */
1699 /*                                                                           */
1700 /*  Opens a text object at the given coords.                                 */
1701 /*                                                                           */
1702 /*****************************************************************************/
1703 
PDFText_OpenX(FILE * in_fp,int hpos)1704 void PDFText_OpenX(FILE* in_fp, int hpos)
1705 {
1706   PDFText_OpenBT(in_fp);
1707   PDFText_MoveToXAndOpen(in_fp, hpos);
1708 }
1709 
1710 
1711 /*****************************************************************************/
1712 /*                                                                           */
1713 /*  void PDFText_Open(FILE* in_fp)                                           */
1714 /*                                                                           */
1715 /*  Opens a text object.                                                     */
1716 /*                                                                           */
1717 /*****************************************************************************/
1718 
PDFText_Open(FILE * in_fp)1719 void PDFText_Open(FILE* in_fp)
1720 {
1721   if (g_TJ_pending)
1722   {
1723     g_TJ_pending = FALSE;		/* clear it */
1724     Assert(g_ET_pending == TRUE, no_fpos);
1725     g_ET_pending = FALSE;		/* clear it */
1726   }
1727   else
1728   {
1729     PDFText_OpenBT(in_fp);
1730     PDFText_OpenString(in_fp);
1731   }
1732 }
1733 
1734 
1735 /*****************************************************************************/
1736 /*                                                                           */
1737 /*  void PDFText_Kern(FILE* in_fp, int in_kern)                              */
1738 /*                                                                           */
1739 /*  Apply kerning to a text string.                                          */
1740 /*                                                                           */
1741 /*  Note: in_kern is in 1/1000 of font size                                  */
1742 /*                                                                           */
1743 /*****************************************************************************/
1744 
PDFText_Kern(FILE * in_fp,int in_kern)1745 void PDFText_Kern(FILE* in_fp, int in_kern)
1746 {
1747   t_tempbuf str;
1748 
1749   /* sprintf(str, ")%d(", -in_kern * 1000 / g_text_font_size_in_ems); */
1750   sprintf(str, ")%d(", -in_kern);
1751   PDFPage_Write(in_fp, str);
1752 }
1753 
1754 
1755 /*****************************************************************************/
1756 /*                                                                           */
1757 /*  void PDFText_Close(FILE* in_fp)                                          */
1758 /*                                                                           */
1759 /*  Closes a previously opened text object.                                  */
1760 /*                                                                           */
1761 /*****************************************************************************/
1762 
PDFText_Close(FILE * in_fp)1763 void PDFText_Close(FILE* in_fp)
1764 {
1765   /* PDFPage_Begin(in_fp); - shouldn't be needed */
1766   Assert(g_page_contents_obj_num != 0, no_fpos);
1767 
1768   g_TJ_pending = TRUE;
1769   /* PDFPage_Write(in_fp, ")] TJ\n"); */
1770   g_ET_pending = TRUE;
1771 }
1772 
1773 
1774 #ifdef USE_MATRICES
1775 
1776 /*****************************************************************************/
1777 /*                                                                           */
1778 /*  void PDF_Matrix_XY(double* in_out_x, double* in_out_y)                   */
1779 /*                                                                           */
1780 /*  Returns (x, y) after applying the current matrix:                        */
1781 /*                                                                           */
1782 /*                                  [ a b 0 ]                                */
1783 /*  [ x y 1 ]       x       [ c d 0 ]       =       [ ax+cy+e  bx+dy+f  1 ]  */
1784 /*                                  [ e f 1 ]                                */
1785 /*                                                                           */
1786 /*****************************************************************************/
1787 
PDF_Matrix_XY(double * in_out_x,double * in_out_y)1788 static void PDF_Matrix_XY(double* in_out_x, double* in_out_y)
1789 {
1790   double result_x, result_y;
1791 
1792   result_x = g_cur_matrix[0] * *in_out_x + g_cur_matrix[3] * *in_out_y +
1793     g_cur_matrix[6];
1794   result_y = g_cur_matrix[1] * *in_out_x + g_cur_matrix[4] * *in_out_y +
1795     g_cur_matrix[7];
1796   *in_out_x = result_x;
1797   *in_out_y = result_y;
1798 }
1799 
1800 
1801 /*****************************************************************************/
1802 /*                                                                           */
1803 /*  PDF_Matrix_Mul(t_matrix in_left, t_matrix in_right, t_matrix out_result) */
1804 /*                                                                           */
1805 /*  Multiplies the given matrices.                                           */
1806 /*                                                                           */
1807 /*  [ a b 0 ]               [ g h 0 ]               [ ag+bi   ah+bj   0 ]    */
1808 /*  [ c d 0 ]       x       [ i j 0 ]       =       [ cg+di   ch+dj   0 ]    */
1809 /*  [ e f 1 ]               [ k l 1 ]               [ eg+fi+k eh+fj+l 1 ]    */
1810 /*                                                                           */
1811 /*****************************************************************************/
1812 
PDF_Matrix_Mul(t_matrix in_left,t_matrix in_right,t_matrix out_result)1813 static void PDF_Matrix_Mul(t_matrix in_left, t_matrix in_right,
1814   t_matrix out_result)
1815 {
1816   t_matrix result;
1817   result[0] = in_left[0] * in_right[0] + in_left[1] * in_right[3];
1818   result[1] = in_left[0] * in_right[1] + in_left[1] * in_right[4];
1819   result[2] = 0;
1820   result[3] = in_left[3] * in_right[0] + in_left[4] * in_right[3];
1821   result[4] = in_left[3] * in_right[1] + in_left[4] * in_right[4];
1822   result[5] = 0;
1823   result[6] = in_left[6] * in_right[0] + in_left[7] * in_right[3] + in_right[6];
1824   result[7] = in_left[6] * in_right[1] + in_left[7] * in_right[4] + in_right[7];
1825   result[8] = 1;
1826 
1827   memcpy(out_result, result, sizeof(t_matrix));
1828 }
1829 #endif
1830 
1831 
1832 /*****************************************************************************/
1833 /*                                                                           */
1834 /*  void  PDFPage_Scale(float in_h_scale_factor, float in_v_scale_factor)    */
1835 /*                                                                           */
1836 /*  Changes CTM by scale factor:                                             */
1837 /*                                                                           */
1838 /*  [  sh   0  0 ]                                                           */
1839 /*  [   0  sv  0 ]                                                           */
1840 /*  [   0   0  1 ]                                                           */
1841 /*                                                                           */
1842 /*****************************************************************************/
1843 
PDFPage_Scale(FILE * in_fp,float in_h_scale_factor,float in_v_scale_factor)1844 void PDFPage_Scale(FILE* in_fp, float in_h_scale_factor, float in_v_scale_factor)
1845 {
1846 #ifdef USE_MATRICES
1847   t_matrix m = { 0, 0, 0, 0, 0, 0, 0, 0, 1 };
1848   m[0] = in_h_scale_factor;
1849   m[4] = in_v_scale_factor;
1850 
1851   PDF_Matrix_Mul(m, g_cur_matrix, g_cur_matrix);
1852 #else
1853   t_tempbuf str;
1854 
1855   sprintf(str, "%.2f 0 0 %.2f 0 0 cm\n", in_h_scale_factor, in_v_scale_factor);
1856   PDFPage_Write(in_fp, str);
1857 #endif
1858   g_page_h_scale_factor *= in_h_scale_factor;
1859   g_page_v_scale_factor *= in_v_scale_factor;
1860 }
1861 
1862 
1863 /*****************************************************************************/
1864 /*                                                                           */
1865 /*  void  PDFPage_Rotate(FILE* in_fp, float in_angle_in_radians)             */
1866 /*                                                                           */
1867 /*  Changes CTM by rotation factor.                                          */
1868 /*                                                                           */
1869 /*  [  cos a  sin a  0 ]                                                     */
1870 /*  [ -sin a  cos a  0 ]                                                     */
1871 /*  [   0       0    1 ]                                                     */
1872 /*                                                                           */
1873 /*****************************************************************************/
1874 
PDFPage_Rotate(FILE * in_fp,float in_angle_in_radians)1875 void PDFPage_Rotate(FILE* in_fp, float in_angle_in_radians)
1876 {
1877   float cos_radians = cos(in_angle_in_radians);
1878   float sin_radians = sin(in_angle_in_radians);
1879 #ifdef USE_MATRICES
1880   t_matrix m = { 0, 0, 0, 0, 0, 0, 0, 0, 1 };
1881   m[0] = m[4] = cos_radians;
1882   m[1] = sin_radians;
1883   m[3] = -sin_radians;
1884   PDF_Matrix_Mul(m, g_cur_matrix, g_cur_matrix);
1885 #else
1886   t_tempbuf str;
1887 
1888   sprintf(str, "%.2f %.2f %.2f %.2f 0 0 cm\n", cos_radians, sin_radians,
1889     -sin_radians, cos_radians);
1890   PDFPage_Write(in_fp, str);
1891 #endif
1892 }
1893 
1894 
1895 /*****************************************************************************/
1896 /*                                                                           */
1897 /*  void  PDFPage_Translate(FILE* in_fp, float in_delta_h, float in_delta_v) */
1898 /*                                                                           */
1899 /*  Changes CTM by translation:                                              */
1900 /*                                                                           */
1901 /*  [  1  0  0 ]                                                             */
1902 /*  [  0  1  0 ]                                                             */
1903 /*  [  dh dv 1 ]                                                             */
1904 /*                                                                           */
1905 /*****************************************************************************/
1906 
PDFPage_Translate(FILE * in_fp,float in_delta_h,float in_delta_v)1907 void PDFPage_Translate(FILE* in_fp, float in_delta_h, float in_delta_v)
1908 {
1909 #ifdef USE_MATRICES
1910   t_matrix m = { 1, 0, 0, 0, 1, 0, 0, 0, 1 };
1911   m[6] = in_delta_h;
1912   m[7] = in_delta_v;
1913   PDF_Matrix_Mul(m, g_cur_matrix, g_cur_matrix);
1914 #else
1915   t_tempbuf str;
1916 
1917   sprintf(str, "1 0 0 1 %.2f %.2f cm\n", in_delta_h, in_delta_v);
1918   PDFPage_Write(in_fp, str);
1919 #endif
1920   g_page_h_origin += in_delta_h;
1921   g_page_v_origin += in_delta_v;
1922 }
1923 
1924 
1925 /*****************************************************************************/
1926 /*                                                                           */
1927 /*  void PDFTargetAnnot_New(FULL_CHAR* in_annot_name, ...)                   */
1928 /*                                                                           */
1929 /*  Create a new target annotation entry.                                    */
1930 /*                                                                           */
1931 /*****************************************************************************/
1932 
PDFTargetAnnot_New(FULL_CHAR * in_annot_name,unsigned int in_annot_name_length,int in_ll_x,int in_ll_y,int in_ur_x,int in_ur_y,BOOLEAN in_for_export)1933 static void PDFTargetAnnot_New(FULL_CHAR* in_annot_name,
1934   unsigned int in_annot_name_length, int in_ll_x, int in_ll_y, int in_ur_x,
1935   int in_ur_y, BOOLEAN in_for_export)
1936 {
1937   t_target_annot_entry_ptr entry =
1938     (t_target_annot_entry_ptr) malloc(sizeof(t_target_annot_entry));
1939 
1940   if (entry == NULL)
1941     Error(48, 16, "PDFTargetAnnot_New: run out of memory", FATAL, no_fpos);
1942 
1943   entry->m_name = (FULL_CHAR*) malloc(in_annot_name_length + 1);
1944   if (entry->m_name == NULL)
1945     Error(48, 17, "PDFTargetAnnot_New: run out of memory", FATAL, no_fpos);
1946   memcpy(entry->m_name, in_annot_name, in_annot_name_length);
1947   entry->m_name[in_annot_name_length] = '\0';
1948 
1949   Assert(g_page_contents_obj_num != 0, no_fpos);
1950   entry->m_page_object_num = g_page_object_num;
1951 
1952   entry->m_ll_x = in_ll_x;
1953   entry->m_ll_y = in_ll_y;
1954   entry->m_ur_x = in_ur_x;
1955   entry->m_ur_y = in_ur_y;
1956   entry->m_for_export = in_for_export;
1957 
1958   entry->m_next_entry = g_target_annot_list;
1959   g_target_annot_list = entry;
1960 
1961   if (in_for_export)
1962     g_has_exported_targets = in_for_export;
1963 }
1964 
1965 
1966 /*****************************************************************************/
1967 /*                                                                           */
1968 /*  t_target_annot_entry_ptr PDFTargetAnnot_Find(FULL_CHAR* in_annot_name)   */
1969 /*                                                                           */
1970 /*  Finds an annotation. Returns NULL if not found.                          */
1971 /*                                                                           */
1972 /*****************************************************************************/
1973 
PDFTargetAnnot_Find(FULL_CHAR * in_annot_name)1974 static t_target_annot_entry_ptr PDFTargetAnnot_Find(FULL_CHAR* in_annot_name)
1975 {
1976   t_target_annot_entry_ptr entry = g_target_annot_list;
1977 
1978   /* this takes O(n) time; may need re-implementing if speed is a factor */
1979   while (entry != NULL)
1980   {
1981     if (strcmp((char*) in_annot_name, (char*) entry->m_name) == 0)
1982       break;
1983     entry = entry->m_next_entry;
1984   }
1985 
1986   return entry;
1987 }
1988 
1989 
1990 /*****************************************************************************/
1991 /*                                                                           */
1992 /*  PDFSourceAnnot_Write(FILE* in_fp,                                        */
1993 /*    t_source_annot_entry_ptr in_source_entry)                              */
1994 /*                                                                           */
1995 /*  Write an annot which specifies the source and target of the link.        */
1996 /*                                                                           */
1997 /*****************************************************************************/
1998 
PDFSourceAnnot_Write(FILE * in_fp,t_source_annot_entry_ptr in_entry)1999 static void PDFSourceAnnot_Write(FILE* in_fp, t_source_annot_entry_ptr in_entry)
2000 {
2001   t_target_annot_entry_ptr target;
2002 
2003   Assert(in_entry != NULL, no_fpos);
2004 
2005   target = in_entry->m_target;
2006 
2007   /* if it is an unresolved forward link then exit */
2008   if ( (in_entry->m_link_type == k_link_source) && (target == NULL) )
2009     return;
2010 
2011   /* green light: write it out */
2012   if (g_PDF_debug)
2013   {
2014     fprintf(in_fp, "%%\n%% annotation in page object # %u to %s:\n%%\n",
2015       in_entry->m_this_page_object_num, in_entry->m_target->m_name);
2016   }
2017 
2018   PDFObject_WriteObj(in_fp, in_entry->m_this_object_num);
2019   fprintf(in_fp, "<<\n/Type /Annot\n/Subtype /Link\n"
2020     /* this is what Adobe does (it's also more flexible) */
2021     "/Rect [ %d %d %d %d ]\n/Border [ 0 0 0 ]\n",
2022     /* "/BS << /Type /Border /S /U >>\n" */
2023     /* border appearance is "underline" */
2024     in_entry->m_ll_x, in_entry->m_ll_y, in_entry->m_ur_x, in_entry->m_ur_y);
2025 
2026   switch (in_entry->m_link_type)
2027   {
2028     case k_link_source:
2029 
2030       fprintf(in_fp, "/Dest [ ");
2031       PDFObject_WriteRef(in_fp, in_entry->m_target->m_page_object_num);
2032       switch (in_entry->m_dest_option)
2033       {
2034 	case kFitNoChange:
2035 
2036 	  fprintf(in_fp, " /XYZ null null null");
2037 	  /* NB NO BREAK */
2038 
2039 	case kFit:
2040 
2041 	  fprintf(in_fp, " /Fit");
2042 	  break;
2043 
2044 
2045 	case kFitH:
2046 
2047 	  /* [ /FitH top ]: fit the width of the page to the window; top    */
2048 	  /* specifies the y-coordinate of the top edge of the window       */
2049 	  fprintf(in_fp, " /FitH %u", target->m_ur_y);
2050 	  break;
2051 
2052 
2053 	case kFitV:
2054 
2055 	  /* [ /FitV left ]: fit the height of the page to the window;      */
2056 	  /* left specifies the x-coordinate of the left edge of the window */
2057 	  fprintf(in_fp, " /FitV %u", target->m_ll_x);
2058 	  break;
2059 
2060 
2061 	case kFitR:
2062 
2063 	  /* [ /FitR left bottom right top ]: fit the rectangle specified   */
2064 	  /* by left bottom right top in the window. If the height (top -   */
2065 	  /* bottom) and width (right - left) imply different zoom factors, */
2066 	  /* the numerically smaller zoom factor is used, to ensure that    */
2067 	  /* the specified rectangle fits in the window                     */
2068 	  fprintf(in_fp, " /FitR %u %u %u %u", target->m_ll_x, target->m_ll_y,
2069 	    target->m_ur_x, target->m_ur_y);
2070 	  break;
2071 
2072 
2073 	case kFitB:
2074 
2075 	  /* [ /FitB ]: fit the page's bounding box to the window           */
2076 	  fprintf(in_fp, " /FitB");
2077 	  break;
2078 
2079 
2080 	case kFitBH:
2081 
2082 	  /* [ /FitBH top ]: fit the width of the page's bounding box to    */
2083 	  /* the window. top specifies the y-coord of top edge of window    */
2084 	  fprintf(in_fp, " /FitBH %u", target->m_ur_y);
2085 	  break;
2086 
2087 
2088 	case kFitBV:
2089 
2090 	  /* [ /FitBV left ]: fit the height of the page' bounding box to   */
2091 	  /* the window. left specifies the x-coordinate of the left edge   */
2092 	  /* of the window                                                  */
2093 	  fprintf(in_fp, " /FitBV %u", target->m_ll_x);
2094 	  break;
2095 
2096 
2097 	default:
2098 
2099 	  Error(48, 18, "PDFSourceAnnot_Write: invalid link dest option",
2100 	    FATAL, no_fpos);
2101       }
2102       fprintf(in_fp, " ]\n");
2103       break;
2104 
2105 
2106     case k_link_external:
2107 
2108 #if 1	/* required wrapper for URLs is now in the Lout libraries */
2109       fprintf(in_fp, "/A << /Type /Action /S /GoToR /D (%s) /F\n"
2110 	/* <= split across lines for LONG file specs */
2111 	"(%s) >>\n", in_entry->m_name, in_entry->m_file_spec);
2112 #else
2113       if (in_entry->m_file_spec[0] != '<')
2114       {
2115 	/* note: destination/target is specified as a string, as is file spec */
2116 	fprintf(in_fp, "/A << /Type /Action /S /GoToR /D (%s) /F\n"
2117 	  /* <= split across lines for LONG file specs */
2118 	  "(%s) >>\n", in_entry->m_name, in_entry->m_file_spec);
2119       }
2120       else
2121       {
2122         /* if file spec starts with '<' then URL, eg <http://www.adobe.com> */
2123 	Assert(in_entry->m_file_spec[strlen((char*) in_entry->m_file_spec)-1]
2124 	  == '>', no_fpos);
2125 	fprintf(in_fp, "/A << /Type /Action /S /GoToR /D (%s) /F\n"
2126 	  /* <= split across lines for LONG file specs */
2127 	  "<< /FS /URL /F (%s) >> >>\n", in_entry->m_name, in_entry->m_file_spec);
2128       }
2129 #endif
2130       break;
2131 
2132 
2133     case k_link_URI:
2134 
2135       fprintf(in_fp, "/A << /Type /Action /S /URI /URI\n"
2136 	/* <= split across lines for LONG URI's */
2137 	"(%s) >>\n", in_entry->m_name);
2138       break;
2139 
2140 
2141     case k_link_target:
2142     case k_link_target_for_export:
2143     case kNumberOfLinkKeywords:
2144 
2145       break;
2146   }
2147 
2148   fprintf(in_fp, ">>\nendobj\n");
2149   in_entry->m_written_to_PDF_file = TRUE;
2150 }
2151 
2152 
2153 /*****************************************************************************/
2154 /*                                                                           */
2155 /*  void PDFSourceAnnot_New(FULL_CHAR* in_annot_name)                        */
2156 /*                                                                           */
2157 /*  Create an entry in the g_source_annot_list which links to in_annot_name. */
2158 /*                                                                           */
2159 /*****************************************************************************/
2160 
2161 static t_source_annot_entry_ptr
PDFSourceAnnot_New(PDF_LINK_KEYWORD in_link_type,FULL_CHAR * in_annot_name,unsigned int in_annot_name_length,int in_ll_x,int in_ll_y,int in_ur_x,int in_ur_y,PDF_LINK_DEST_OPTION in_link_dest_option)2162 PDFSourceAnnot_New(PDF_LINK_KEYWORD in_link_type, FULL_CHAR* in_annot_name,
2163   unsigned int in_annot_name_length, int in_ll_x, int in_ll_y, int in_ur_x,
2164   int in_ur_y, PDF_LINK_DEST_OPTION in_link_dest_option)
2165 {
2166   t_target_annot_entry_ptr target = NULL;
2167   t_source_annot_entry_ptr entry =
2168     (t_source_annot_entry_ptr) malloc(sizeof(t_source_annot_entry));
2169 
2170   if (entry == NULL)
2171     Error(48, 19, "PDFSourceAnnot_New: run out of memory", FATAL, no_fpos);
2172 
2173   entry->m_ll_x = in_ll_x;
2174   entry->m_ll_y = in_ll_y;
2175   entry->m_ur_x = in_ur_x;
2176   entry->m_ur_y = in_ur_y;
2177 
2178   entry->m_this_object_num = PDFObject_New(/* in_fp */);
2179   entry->m_this_page_object_num = g_page_object_num;
2180   entry->m_link_type = in_link_type;
2181   Assert((in_link_dest_option >= kFitNoChange) &&
2182     (in_link_dest_option <= kFitBV), no_fpos);
2183   entry->m_dest_option = in_link_dest_option;
2184   entry->m_file_spec = NULL;
2185   entry->m_written_to_PDF_file = FALSE;
2186 
2187   if (in_link_type == k_link_source)
2188     target = PDFTargetAnnot_Find(in_annot_name);
2189 
2190   if (target != NULL)
2191   {
2192     entry->m_target = target;
2193     entry->m_name = NULL;
2194   }
2195   else
2196   {
2197     entry->m_target = NULL;	/* fwd link */
2198     entry->m_name = (FULL_CHAR*) malloc(in_annot_name_length + 1);
2199     if (entry->m_name == NULL)
2200       Error(48, 20, "PDFSourceAnnot_New: run out of memory", FATAL, no_fpos);
2201     memcpy(entry->m_name, in_annot_name, in_annot_name_length);
2202     entry->m_name[in_annot_name_length] = '\0';
2203   }
2204 
2205   entry->m_next_entry = g_source_annot_list;
2206   g_source_annot_list = entry;
2207 
2208   return entry;
2209 }
2210 
2211 
2212 /*****************************************************************************/
2213 /*                                                                           */
2214 /*  PDFSourceAnnot_Dispose(t_source_annot_entry_ptr in_source_annot)         */
2215 /*                                                                           */
2216 /*  Dispose of a source annot entry; returns the next entry in the list.     */
2217 /*                                                                           */
2218 /*****************************************************************************/
2219 
2220 static t_source_annot_entry_ptr
PDFSourceAnnot_Dispose(t_source_annot_entry_ptr in_source_annot)2221   PDFSourceAnnot_Dispose(t_source_annot_entry_ptr in_source_annot)
2222 {
2223   t_source_annot_entry_ptr next_entry = in_source_annot->m_next_entry;
2224 
2225   if (in_source_annot->m_name != NULL)
2226     free(in_source_annot->m_name);
2227   if (in_source_annot->m_file_spec != NULL)
2228     free(in_source_annot->m_file_spec);
2229   free(in_source_annot);
2230   return next_entry;
2231 }
2232 
2233 
2234 /*****************************************************************************/
2235 /*                                                                           */
2236 /*  float  PDFPage_GetFloat(FULL_CHAR* in_str)                               */
2237 /*                                                                           */
2238 /*  Outputs an appropriate PDF string for drawing a graphic element.         */
2239 /*                                                                           */
2240 /*****************************************************************************/
2241 
PDFPage_GetFloat(FULL_CHAR * in_str,float * out_value)2242 static FULL_CHAR *PDFPage_GetFloat(FULL_CHAR* in_str, float* out_value)
2243 {
2244   if (sscanf((char*) in_str, "%f", out_value) == 1)
2245   {
2246     /* skip (presumed) floating point number: [ ]*[+|-][0-9.]* */
2247     while (isspace(*in_str))
2248       in_str++;
2249     if ( (*in_str == '-') || (*in_str == '+') )
2250       in_str++;
2251     while (isdigit(*in_str) || (*in_str == '.'))
2252       in_str++;
2253   }
2254   else Error(48, 21, "PDFPage_GetFloat: unable to evaluate number for Lout graphic keyword processing",
2255     FATAL, no_fpos);
2256   return in_str;
2257 }
2258 
2259 
2260 /*****************************************************************************/
2261 /*                                                                           */
2262 /*  int PDFKeyword_Find(int in_number_of_array_elements,                     */
2263 /*    char* in_keyword_array[], FULL_CHAR* in_str)                           */
2264 /*                                                                           */
2265 /*  Return index into keyword array if an element matches the given string.  */
2266 /*  Returns -1 if not found.                                                 */
2267 /*                                                                           */
2268 /*****************************************************************************/
2269 
PDFKeyword_Find(int in_number_of_array_elements,char * in_keyword_array[],FULL_CHAR * in_str)2270 static int PDFKeyword_Find(int in_number_of_array_elements,
2271   char* in_keyword_array[], FULL_CHAR* in_str)
2272 {
2273   unsigned int i;
2274 
2275   /* look for keyword */
2276   for (i = 0; i < in_number_of_array_elements; i++)
2277   {
2278     unsigned int len = strlen(in_keyword_array[i]);
2279 
2280     if (memcmp(in_keyword_array[i], in_str, len) == 0)
2281       break;
2282   }
2283 
2284   return (i < in_number_of_array_elements) ? i : -1;
2285 }
2286 
2287 
2288 /*****************************************************************************/
2289 /*                                                                           */
2290 /*  FULL_CHAR *PDFPage_ProcessGraphicsKeyword(FULL_CHAR* charPtr, int i)     */
2291 /*                                                                           */
2292 /*  Processes a link keyword.                                                */
2293 /*                                                                           */
2294 /*****************************************************************************/
2295 
2296 #if 0	/* this function is no longer used */
2297 
2298 static FULL_CHAR *PDFPage_ProcessGraphicsKeyword(FULL_CHAR* charPtr, int i,
2299   char** strPtr)
2300 {
2301   float value;
2302 
2303   /* if need be, expand this later to a full blown expression evaluator (ugh) */
2304   switch (*charPtr)
2305   {
2306     case '+':
2307 
2308       Assert(FALSE, no_fpos);
2309       charPtr = PDFPage_GetFloat(++charPtr, &value);
2310       sprintf(*strPtr, "%.2f", g_graphics_vars[i] + value);
2311       break;
2312 
2313 
2314     case '-':
2315 
2316       Assert(FALSE, no_fpos);
2317       charPtr = PDFPage_GetFloat(++charPtr, &value);
2318       sprintf(*strPtr, "%.2f", g_graphics_vars[i] - value);
2319       break;
2320 
2321 
2322     case '*':
2323 
2324       Assert(FALSE, no_fpos);
2325       charPtr = PDFPage_GetFloat(++charPtr, &value);
2326       sprintf(*strPtr, "%.2f", g_graphics_vars[i] * value);
2327       break;
2328 
2329 
2330     case '/':
2331 
2332       Assert(FALSE, no_fpos);
2333       charPtr = PDFPage_GetFloat(++charPtr, &value);
2334       Assert(value != 0, no_fpos);	/* not great since value is a float... */
2335       sprintf(*strPtr, "%.2f", g_graphics_vars[i] / value);
2336       break;
2337 
2338 
2339     default:
2340 
2341       sprintf(*strPtr, "%d", g_graphics_vars[i]);
2342       break;
2343   }
2344   *strPtr += strlen(*strPtr);
2345   return charPtr;
2346 }
2347 
2348 #endif
2349 
2350 
2351 /*****************************************************************************/
2352 /*                                                                           */
2353 /*  void PDFPage_ProcessLinkKeyword(void)                                    */
2354 /*                                                                           */
2355 /*  Processes a link keyword.                                                */
2356 /*                                                                           */
2357 /*****************************************************************************/
2358 
PDFPage_ProcessLinkKeyword(void)2359 static void PDFPage_ProcessLinkKeyword(void)
2360 {
2361   FULL_CHAR* charPtr = (FULL_CHAR*) g_link;
2362   PDF_LINK_KEYWORD keyword = g_link_keyword;
2363   unsigned int link_len = 0;
2364   FULL_CHAR* link_name = charPtr;
2365 
2366   /* scan for name of link; scan until end of string or until ' __' reached  */
2367   /* (scan for name of link; scan until end of string or whitespace reached) */
2368 #if 1
2369 
2370   FULL_CHAR* parm = NULL;
2371   debug1(DPD, D, "PDFPage_ProcessLinkKeyword(g_link = %s", g_link);
2372 
2373   while ((*charPtr != '\0') &&
2374     !(isspace(charPtr[0]) && (charPtr[1] == '_') && (charPtr[2] == '_')))
2375   {
2376     link_len++;
2377     charPtr++;
2378   }
2379 
2380   if (*charPtr != '\0')
2381     parm = ++charPtr;
2382 
2383   while (*charPtr != '\0')
2384     charPtr++;
2385 #else
2386   while ((*charPtr != '\0') && ! isspace(*charPtr))
2387   {
2388     link_len++;
2389     charPtr++;
2390   }
2391 #endif
2392   if (link_len == 0)
2393     Error(48, 22, "PDFPage_ProcessLinkKeyword: empty link-name / URI; ignored.",
2394       WARN, no_fpos);
2395   else
2396   {
2397 
2398     /* see documentaton for @Graphic for the meaning of the x, y parms */
2399     /* translate the object's box into PDF's default user space */
2400     int ll_x = g_page_h_origin * g_page_h_scale_factor;
2401     int ll_y = g_page_v_origin * g_page_v_scale_factor;
2402     int ur_x = (g_page_h_origin + g_graphics_vars[k_xsize]) * g_page_h_scale_factor;
2403     int ur_y = (g_page_v_origin + g_graphics_vars[k_ysize]) * g_page_v_scale_factor;
2404 
2405     /* remove this block later (it produces debugging output): */
2406 #if 0
2407     {
2408       t_tempbuf strz = "PDFPage_ProcessLinkKeyword: ";
2409       switch (keyword)
2410       {
2411 	case k_link_source:
2412 
2413 	  strcat(strz, "link_source           =");
2414 	  break;
2415 
2416 
2417 	case k_link_external:
2418 
2419 	  strcat(strz, "link_external         =");
2420 	  break;
2421 
2422 
2423 	case k_link_URI:
2424 
2425 	  strcat(strz, "link_URI              =");
2426 	  break;
2427 
2428 
2429 	case k_link_target:
2430 
2431 	  strcat(strz, "link_target           =");
2432 	  break;
2433 
2434 
2435 	case k_link_target_for_export:
2436 
2437 	  strcat(strz, "link_target_for_export=");
2438 	  break;
2439       }
2440       strcat(strz, (char*) link_name);
2441       fprintf(stderr, "%s", strz);
2442       /* Err or(48, 23, strz, WARN, no_fpos); */
2443     }
2444 #endif
2445     switch (keyword)
2446     {
2447       case k_link_source:
2448 
2449 	{
2450 	  int j;
2451 
2452 	  /* if there is a dest option specified then get it */
2453 	  if (parm != NULL)
2454 	  {
2455 	    j = PDFKeyword_Find(kNumberOfDestLinkOptions, g_dest_link_options,
2456 		charPtr);
2457 	    if (j >= 0)		/* note signed comparison */
2458 	      charPtr += strlen(g_dest_link_options[j]);
2459 	    else
2460 	    {
2461 	      j = (int) kFitNoChange;	/* default */
2462 	      /* must consume the rest of the string */
2463 	      while (*charPtr != '\0')
2464 		charPtr++;
2465 	      link_len = charPtr - link_name;
2466 	    }
2467 	  }
2468 	  else
2469 	    j = (int) kFitNoChange;	/* default */
2470 
2471 	  PDFSourceAnnot_New(keyword, link_name, link_len,
2472 	    ll_x, ll_y, ur_x, ur_y, (PDF_LINK_DEST_OPTION) j);
2473 	  break;
2474 	}
2475 
2476 
2477       case k_link_external:
2478       case k_link_URI:
2479 
2480 	{
2481 	  t_source_annot_entry_ptr source;
2482 	  source = PDFSourceAnnot_New(keyword, link_name, link_len, ll_x,
2483 	    ll_y, ur_x, ur_y, (PDF_LINK_DEST_OPTION) 0 /* doesn't matter */);
2484 	  if (keyword == k_link_external)
2485 	  {
2486 	    int j;
2487 
2488 	    link_len = 0;
2489 
2490 	    if (parm != NULL)
2491 	    {
2492 	      j = PDFKeyword_Find(1, g_external_file_spec_keyword, parm);
2493 	      if (j == 0)
2494 	      {
2495 		parm += strlen(g_external_file_spec_keyword[0]);
2496 		link_len = strlen((char*) parm);
2497 #if 0
2498 		/* scan for name of file spec; scan until end of string or */
2499 		/* until whitespace reached                                */
2500 		link_name = charPtr;
2501 		while ((*charPtr != '\0') && ! isspace(*charPtr))
2502 		{
2503 		  link_len++;
2504 		  charPtr++;
2505 		}
2506 #endif
2507 	      }
2508 	    }
2509 
2510 	    if (link_len == 0)
2511 	      Error(48, 24, "PDFPage_ProcessLinkKeyword: empty file spec",
2512 		FATAL, no_fpos);
2513 	    else
2514 	    {
2515 	      source->m_file_spec = (FULL_CHAR*) malloc(link_len + 1);
2516 	      if (source->m_file_spec == NULL)
2517 		Error(48, 25, "PDFPage_ProcessLinkKeyword: out of memory",
2518 		  FATAL, no_fpos);
2519 #if 1
2520 	      strcpy((char*) source->m_file_spec, (char*) parm);
2521 #else
2522 	      memcpy(source->m_file_spec, link_name, link_len);
2523 	      source->m_file_spec[link_len] = '\0';
2524 #endif
2525 	    }
2526 	  }
2527 	  break;
2528 	}
2529 
2530 
2531       case k_link_target:
2532       case k_link_target_for_export:
2533 
2534 	PDFTargetAnnot_New(link_name, link_len, ll_x, ll_y, ur_x, ur_y,
2535 	  keyword == k_link_target_for_export);
2536 	break;
2537 
2538 
2539       case kNumberOfLinkKeywords:
2540 	break;
2541 
2542     } /* switch */
2543   } /* else */
2544 
2545   debug0(DPD, D, "PDFPage_ProcessLinkKeyword returning");
2546   /* return charPtr; */
2547 } /* PDFPage_ProcessLinkKeyword */
2548 
2549 
2550 /*****************************************************************************/
2551 /*                                                                           */
2552 /*  FULL_CHAR* PDFPage_ProcessDocInfoKeyword(FULL_CHAR* charPtr, int i)      */
2553 /*                                                                           */
2554 /*  Processes a document info keyword.                                       */
2555 /*                                                                           */
2556 /*****************************************************************************/
2557 
PDFPage_ProcessDocInfoKeyword(FULL_CHAR * charPtr,int i)2558 static FULL_CHAR *PDFPage_ProcessDocInfoKeyword(FULL_CHAR* charPtr, int i)
2559 {
2560   switch (i)
2561   {
2562     case k_author:
2563 
2564       if (g_doc_author != NULL)
2565 	free(g_doc_author);
2566       g_doc_author = (FULL_CHAR*) malloc(strlen((char*) charPtr) + 1);
2567       if (g_doc_author == NULL)
2568 	Error(48, 26, "PDFPage_ProcessDocInfoKeyword: no memory for __author=",
2569 	  WARN, no_fpos);
2570       else
2571 	strcpy((char*) g_doc_author, (char*) charPtr);
2572       break;
2573 
2574 
2575     case k_title:
2576 
2577       if (g_doc_title != NULL)
2578 	free(g_doc_title);
2579       g_doc_title = (FULL_CHAR*) malloc(strlen((char*) charPtr) + 1);
2580       if (g_doc_title == NULL)
2581 	Error(48, 27, "PDFPage_ProcessDocInfoKeyword: no memory for __title=",
2582 	  WARN, no_fpos);
2583        else
2584 	strcpy((char*) g_doc_title, (char*) charPtr);
2585       break;
2586 
2587 
2588     case k_subject:
2589 
2590       if (g_doc_subject != NULL)
2591 	free(g_doc_subject);
2592       g_doc_subject = (FULL_CHAR*) malloc(strlen((char*) charPtr) + 1);
2593       if (g_doc_subject == NULL)
2594 	Error(47, 28, "PDFPage_ProcessDocInfoKeyword: no memory for __subject=",
2595 	  WARN, no_fpos);
2596       else
2597 	strcpy((char*) g_doc_subject, (char*) charPtr);
2598       break;
2599 
2600 
2601     case k_keywords:
2602       if (g_doc_keywords != NULL)
2603 	free(g_doc_keywords);
2604       g_doc_keywords = (FULL_CHAR*) malloc(strlen((char*) charPtr) + 1);
2605       if (g_doc_keywords == NULL)
2606 	Error(48, 29, "PDFPage_ProcessDocInfoKeyword: no memory for __keywords=",
2607 	  WARN, no_fpos);
2608       else
2609 	strcpy((char*) g_doc_keywords, (char*) charPtr);
2610       break;
2611 
2612   }
2613   return (charPtr + strlen((char*) charPtr));
2614 }
2615 
2616 
2617 /*****************************************************************************/
2618 /*                                                                           */
2619 /*  void  PDFPage_EvalExpr(char* inExpr)                                     */
2620 /*                                                                           */
2621 /*  Evaluate collected expression in the given expression buffer.            */
2622 /*                                                                           */
2623 /*****************************************************************************/
2624 
PDFPage_EvalExpr(char * inExpr,float * outValue)2625 static char *PDFPage_EvalExpr(char* inExpr, float* outValue)
2626 {
2627   int i;
2628   char* chp = inExpr;
2629 
2630   while (isspace( (int) *chp))	/* ignore leading white space */
2631     chp++;
2632 
2633   while (*chp == '_')
2634     chp++;
2635 
2636   while (*chp == '+')	/* ignore unary + */
2637     chp++;
2638 
2639   if (isdigit((int) *chp) || (*chp == '.'))
2640   {
2641     chp = (char*) PDFPage_GetFloat((FULL_CHAR*) chp, outValue);
2642   }
2643   else if (*chp == '-')	/* handle unary negation */
2644   {
2645     float val;
2646 
2647     chp = PDFPage_EvalExpr(++chp, &val);
2648     *outValue = -val;
2649   }
2650   else
2651   {
2652     i = PDFKeyword_Find(kNumberOfArithmeticKeywords,
2653 	  g_arithmetic_keywords, (FULL_CHAR*) chp);
2654     if (i >= 0)
2655     {
2656       float val1, val2;
2657 
2658       chp += strlen(g_arithmetic_keywords[i]);
2659 
2660       while (isspace( (int) *chp))
2661 	chp++;
2662       if (*chp != '(')
2663 	Error(48, 30, "PDFPage_EvalExpr: '(' expected", FATAL, no_fpos);
2664       chp = PDFPage_EvalExpr(++chp, &val1);
2665       if ( (i <= k_div) || (i == k_pick) )
2666       {
2667 	int count;
2668 
2669 	if (i == k_pick)
2670 	{
2671 	  count = floor(val1);
2672 	  Assert(count != 0, no_fpos);
2673 	}
2674 	else
2675 	  count = 1;
2676 
2677 	if (*chp != ',')
2678 	  Error(48, 31, "PDFPage_EvalExpr: ',' expected", FATAL, no_fpos);
2679 
2680 	do {
2681 	  chp = PDFPage_EvalExpr(++chp, &val2);
2682 	  if ((count != 1) && (*chp == ','))
2683 	    ++chp;
2684 	} while (--count != 0);
2685       }
2686       if (*chp != ')')
2687 	Error(48, 32, "PDFPage_EvalExpr: ')' expected", FATAL, no_fpos);
2688       ++chp;
2689       switch (i)
2690       {
2691 
2692 	case k_add:
2693 	  *outValue = val1 + val2;
2694 	  break;
2695 
2696 
2697 	case k_sub:
2698 
2699 	  *outValue = val1 - val2;
2700 	  break;
2701 
2702 
2703 	case k_mul:
2704 
2705 	  *outValue = val1 * val2;
2706 	  break;
2707 
2708 
2709 	case k_div:
2710 
2711 	  Assert(val2 != 0, no_fpos); /* not great since value is a float... */
2712 	  *outValue = val1 / val2;
2713 	  break;
2714 
2715 
2716 	case k_sin:
2717 
2718 	  *outValue = sin((double) val1 * (double) M_PI / (double) 180.0);
2719 	  break;
2720 
2721 
2722 	case k_cos:
2723 
2724 	  *outValue = cos((double) val1 * (double) M_PI / (double) 180.0);
2725 	  break;
2726 
2727 
2728 	case k_pick:
2729 
2730 	  *outValue = val2;
2731 	  break;
2732       }
2733     }
2734     else
2735     {
2736       i = PDFKeyword_Find(kNumberOfGraphicsKeywords, g_graphic_keywords,
2737 	    (FULL_CHAR*) chp);
2738       if (i >= 0)
2739       {
2740 	chp += strlen(g_graphic_keywords[i]);
2741 	*outValue = g_graphics_vars[i];
2742       }
2743       else
2744       {
2745 	i = PDFKeyword_Find(kNumberOfUnitKeywords, g_unit_keywords, (FULL_CHAR*) chp);
2746 	if (i >= 0)
2747 	{
2748 	  chp += strlen(g_unit_keywords[i]);
2749 	  *outValue = g_units[i];
2750 	}
2751 	else
2752 	{
2753 	  Error(48, 33, "PDFPage_EvalExpr: __add, __sub, __mul, __div, or a unit keyword was expected",
2754 	    FATAL, no_fpos);
2755 	}
2756       }
2757     }
2758   }
2759   return chp;
2760 }
2761 
2762 
2763 /*****************************************************************************/
2764 /*                                                                           */
2765 /*  FULL_CHAR *PDFPage_CollectExpr(FULL_CHAR* charPtr)                       */
2766 /*                                                                           */
2767 /*  Collect expression into the expression buffer.                           */
2768 /*                                                                           */
2769 /*****************************************************************************/
2770 
PDFPage_CollectExpr(FULL_CHAR * charPtr,BOOLEAN * outHasResult,float * outResult)2771 static FULL_CHAR *PDFPage_CollectExpr(FULL_CHAR* charPtr, BOOLEAN* outHasResult,
2772   float* outResult)
2773 {
2774   *outHasResult = FALSE;
2775   while (*charPtr != 0)
2776   {
2777     char ch;
2778 
2779     if ( g_expr_index >= sizeof(g_expr) )
2780       Error(48, 34, "PDFPage_CollectExpr: expression too long (max. 512 chars)",
2781 	FATAL, no_fpos);
2782 
2783     g_expr[g_expr_index++] = ch = *charPtr++;
2784     if (ch == '(')
2785       g_expr_depth++;
2786     else if (ch == ')')
2787     {
2788       Assert(g_expr_depth != 0, no_fpos);
2789       g_expr_depth--;
2790       if (g_expr_depth == 0)
2791       {
2792 	g_expr[g_expr_index] = '\0';	/* terminate the string */
2793 	(char*) PDFPage_EvalExpr(g_expr, outResult);
2794 	*outHasResult = TRUE;
2795 	break;	/* exit while */
2796       }
2797     }
2798   }
2799   return charPtr;
2800 }
2801 
2802 
2803 /*****************************************************************************/
2804 /*                                                                           */
2805 /*  FULL_CHAR *PDFPage_CollectLink(FULL_CHAR* charPtr)                       */
2806 /*                                                                           */
2807 /*  Collect link into the link buffer.                                       */
2808 /*                                                                           */
2809 /*****************************************************************************/
2810 
PDFPage_CollectLink(FULL_CHAR * charPtr)2811 static FULL_CHAR *PDFPage_CollectLink(FULL_CHAR* charPtr
2812   /*, BOOLEAN* outHasResult, float* outResult*/)
2813 {
2814   debug1(DPD, D, "PDFPage_CollectLink(\"%s\")", charPtr);
2815   while (*charPtr != 0)
2816   {
2817     char ch;
2818 
2819     if ( g_link_index >= sizeof(g_link) )
2820       Error(48, 35, "PDFPage_CollectLink: link too long (max. 512 chars)",
2821 	FATAL, no_fpos);
2822 
2823     g_link[g_link_index++] = ch = *charPtr++;
2824     if ((ch == '<') && (*charPtr == '<'))
2825     {
2826       g_link[g_link_index++] = *charPtr++;
2827       g_link_depth++;
2828     }
2829     else if ((ch == '>') && (*charPtr == '>'))
2830     {
2831       Assert(g_link_depth != 0, no_fpos);
2832 
2833       g_link_depth--;
2834       if (g_link_depth == 0)
2835       {
2836 	/* I don't want the outermost '<<' '>>' pair */
2837 	g_link[--g_link_index] = '\0';	/* terminate the string */
2838 
2839 	PDFPage_ProcessLinkKeyword();
2840 
2841 	charPtr++;
2842 	break;	/* exit while */
2843       }
2844       else
2845 	g_link[g_link_index++] = *charPtr++;
2846     }
2847   }
2848   debug0(DPD, D, "PDFPage_CollectLink returning");
2849   return charPtr;
2850 }
2851 
2852 
2853 /*****************************************************************************/
2854 /*                                                                           */
2855 /*  void PDFPage_WriteGraphic(FILE* in_fp, FULL_CHAR* in_str)                */
2856 /*                                                                           */
2857 /*  Outputs an appropriate PDF string for drawing a graphic element.         */
2858 /*                                                                           */
2859 /*****************************************************************************/
2860 
PDFPage_WriteGraphic(FILE * in_fp,FULL_CHAR * in_str)2861 void PDFPage_WriteGraphic(FILE* in_fp, FULL_CHAR* in_str)
2862 {
2863   t_tempbuf str;
2864 
2865   FULL_CHAR *charPtr = in_str;
2866   char *strPtr = str;
2867 
2868   if (*charPtr == 0)
2869     return;
2870 
2871   /* if in collecting an expression mode then collect until terminating ')' */
2872   if (g_expr_depth != 0)
2873   {
2874     BOOLEAN hasResult;
2875     float value;
2876 
2877     charPtr = PDFPage_CollectExpr(charPtr, &hasResult, &value);
2878     if (hasResult)
2879     {
2880       sprintf(strPtr, "%.2f", value);
2881       strPtr += strlen(strPtr);
2882     }
2883   }
2884 
2885   /* if in collecting-a-link mode then collect until terminating '>>'        */
2886   if (g_link_depth != 0)
2887     charPtr = PDFPage_CollectLink(charPtr);
2888 
2889   /* scan the string for '__' otherwise output it */
2890   while (*charPtr != 0)
2891   {
2892     int i;
2893     float value;
2894 
2895     Assert(strPtr < (str + sizeof(t_tempbuf)), no_fpos);
2896 
2897     /* look for "__" (double underline) */
2898     if ( (charPtr[0] == '_') && (charPtr[1] == '_') )
2899     {
2900       charPtr += 2;
2901 
2902       /* "in", "cm", "pt", "em", "loutf", "loutv", "louts" */
2903 #if 0
2904       i = PDFKeyword_Find(kNumberOfUnitKeywords, g_unit_keywords, charPtr);
2905       if (i >= 0)
2906       {
2907 	Assert(FALSE, no_fpos);
2908 	charPtr += strlen(g_unit_keywords[i]);	/* skip keyword */
2909 	charPtr = PDFPage_GetFloat(charPtr, &value); /* get value */
2910 	sprintf(strPtr, "%.2f", g_units[i] * value); /* output it */
2911 	strPtr += strlen(strPtr);
2912       }
2913       else
2914 #endif
2915       {
2916 
2917 	/* "xsize", "ysize", "xmark", "ymark" */
2918 	i = PDFKeyword_Find(kNumberOfGraphicsKeywords, g_graphic_keywords, charPtr);
2919 	if (i >= 0)
2920 	{
2921 	  charPtr += strlen(g_graphic_keywords[i]);
2922 #if 1
2923 	  sprintf(strPtr, "%d", g_graphics_vars[i]);
2924 	  strPtr += strlen(strPtr);
2925 #else
2926 	  charPtr = PDFPage_ProcessGraphicsKeyword(charPtr, i, &strPtr);
2927 #endif
2928 	}
2929 	else
2930 	{
2931 	  /* "link_source=<<", "link_target=<<", "link_target_for_export=<<", "link_URI=<<" */
2932 	  i = PDFKeyword_Find(kNumberOfLinkKeywords, g_link_keywords, charPtr);
2933 	  if (i >= 0)
2934 	  {
2935 	    charPtr += strlen(g_link_keywords[i]);
2936 #if 1
2937 	    while (isspace(*charPtr))
2938 	      charPtr++;
2939 
2940 	    g_link_index = 0;
2941 	    g_link_depth++;
2942 	    g_link_keyword = (PDF_LINK_KEYWORD) i;
2943 	    charPtr = PDFPage_CollectLink(charPtr);
2944 #else
2945 	    charPtr = PDFPage_ProcessLinkKeyword(charPtr, (PDF_LINK_KEYWORD) i);
2946 #endif
2947 	  } /* if */
2948 	  else
2949 	  {
2950 
2951 	    /* "author=", "title=", "subject=", "keywords=" */
2952 	    i = PDFKeyword_Find(kNumberOfDocInfoKeywords, g_doc_info_keywords, charPtr);
2953 	    if (i >= 0)
2954 	    {
2955 	      charPtr += strlen(g_doc_info_keywords[i]);
2956 	      charPtr = PDFPage_ProcessDocInfoKeyword(charPtr, i);
2957 	    }
2958 	    else
2959 	    {
2960 
2961 	      /* "add" "sub" "mul" "div", "sin", "cos" */
2962 	      i = PDFKeyword_Find(kNumberOfArithmeticKeywords, g_arithmetic_keywords, charPtr);
2963 	      if (i >= 0)
2964 	      {
2965 		strcpy(g_expr, g_arithmetic_keywords[i]);
2966 		charPtr += strlen(g_arithmetic_keywords[i]);
2967 		while (isspace(*charPtr))
2968 		  charPtr++;
2969 		if (*charPtr != '(')
2970 		  Error(48, 36, "PDFPage_WriteGraphic: '(' expected", FATAL, no_fpos);
2971 
2972 		strcat(g_expr, "(");
2973 		g_expr_index = strlen(g_expr);
2974 		g_expr_depth++;
2975 		{
2976 		  BOOLEAN hasResult;
2977 
2978 		  charPtr = PDFPage_CollectExpr(++charPtr, &hasResult, &value);
2979 		  if (hasResult)
2980 		  {
2981 		    sprintf(strPtr, "%.2f", value);
2982 		    strPtr += strlen(strPtr);
2983 		  }
2984 		}
2985 	      }
2986 	      else
2987 	      {
2988 		/* alert user in case there was a spelling mistake */
2989 		Error(48, 37, "PDFPage_WriteGraphic: '__' encountered while processing @Graphic", WARN, no_fpos);
2990 		*strPtr++ = '_';
2991 		*strPtr++ = '_';
2992 	      } /* else */
2993 	    } /* else */
2994 	  } /* else */
2995 	} /* else */
2996       } /* else */
2997     } /* if */
2998     else
2999     {
3000       *strPtr++ = *charPtr++;
3001     }
3002   }
3003 
3004   *strPtr = 0;
3005 
3006   PDFPage_FlushBuffer(in_fp);	/* this is a marking operation, so flush */
3007   PDFPage_Write(in_fp, str);
3008 }
3009 
3010 
3011 /*****************************************************************************/
3012 /*                                                                           */
3013 /* PDFPage_PrintUnderline(FILE* in_fp, int x1, int x2, int y, int thickness) */
3014 /*                                                                           */
3015 /*  Implements underlining (just draws a horizontal line).                   */
3016 /*                                                                           */
3017 /*****************************************************************************/
3018 
PDFPage_PrintUnderline(FILE * in_fp,int in_x1,int in_x2,int in_y,int in_thickness)3019 void PDFPage_PrintUnderline(FILE* in_fp, int in_x1, int in_x2, int in_y,
3020   int in_thickness)
3021 {
3022   t_tempbuf str;
3023 
3024   /* this is a marking operation, so flush and turn off buffering */
3025   PDFPage_FlushBuffer(in_fp);
3026 
3027   /* fprintf(out_fp, "/ul { gsave setlinewidth dup 3 1 roll\n"); */
3028   /* fprintf(out_fp, "      moveto lineto stroke grestore } bind def\n");  */
3029 
3030   sprintf(str, "q %d w %d %d m %d %d l s Q\n",in_thickness,in_x1,in_y,in_x2,in_y);
3031   PDFPage_Write(in_fp, str);
3032 }
3033 
3034 
3035 /*****************************************************************************/
3036 /*                                                                           */
3037 /*  void PDFPage_Init(FILE* in_fp, float in_scale_factor, int in_line_width) */
3038 /*                                                                           */
3039 /*  Inits the vars for the start of processing a new page.                   */
3040 /*                                                                           */
3041 /*  [ 0 1 2 ]               [ s 0 0 ]                                        */
3042 /*  [ 3 4 5 ]       =       [ 0 s 0 ]                                        */
3043 /*  [ 6 7 8 ]               [ 0 0 1 ]                                        */
3044 /*                                                                           */
3045 /*****************************************************************************/
3046 
PDFPage_Init(FILE * in_fp,float in_scale_factor,int in_line_width)3047 void  PDFPage_Init(FILE* in_fp, float in_scale_factor, int in_line_width)
3048 {
3049 
3050 #ifdef USE_MATRICES
3051   g_cur_matrix[0] = g_cur_matrix[4] = in_scale_factor;
3052   g_cur_matrix[1] = g_cur_matrix[2] = g_cur_matrix[3] =
3053   g_cur_matrix[5] = g_cur_matrix[6] = g_cur_matrix[7] = 0;
3054   g_cur_matrix[8] = 1;
3055   g_matrix_stack = NULL;
3056 #endif
3057 
3058   /* clear/init page vars */
3059   g_page_uses_fonts = FALSE;
3060   g_page_has_text  = FALSE;
3061   g_page_has_graphics = FALSE;
3062 
3063   g_page_contents_obj_num = 0; /* undefined */
3064   g_page_length_obj_num = 0; /* undefined */
3065   g_page_start_offset = 0; /* undefined */
3066   /* g_text_font_size_in_ems = 0; */ /* undefined */
3067 
3068   g_page_h_scale_factor = g_page_v_scale_factor = in_scale_factor;
3069   g_page_h_origin = g_page_v_origin = 0;
3070   g_page_line_width = in_line_width;
3071 
3072   /* ***
3073   g_graphics_vars[k_in] = IN;
3074   g_graphics_vars[k_cm] = CM;
3075   g_graphics_vars[k_pt] = PT;
3076   g_graphics_vars[k_em] = EM;
3077   *** */
3078   g_graphics_vars[k_xsize] = 0; /* undefined */
3079   g_graphics_vars[k_ysize] = 0; /* undefined */
3080   g_graphics_vars[k_xmark] = 0; /* undefined */
3081   g_graphics_vars[k_ymark] = 0; /* undefined */
3082   /* ***
3083   g_graphics_vars[k_loutf] = 0;
3084   g_graphics_vars[k_loutv] = 0;
3085   g_graphics_vars[k_louts] = 0;
3086   *** */
3087 
3088   /* No need to touch k_in other constant units */
3089   g_units[k_loutf] = 0; /* undefined */
3090   g_units[k_loutv] = 0; /* undefined */
3091   g_units[k_louts] = 0; /* undefined */
3092 
3093   g_ET_pending = FALSE;
3094   g_TJ_pending = FALSE;
3095   g_valid_text_matrix = FALSE;	/* Td is not allowed */
3096 
3097   /* mark all fonts "not in use" */
3098   {
3099     t_font_list_entry_ptr entry = g_font_list;
3100     while (entry != NULL) {
3101       entry->m_in_use = FALSE;	/* set the "in use" state to "not in use" */
3102       entry = entry->m_next_font_entry;
3103     }
3104   }
3105 
3106   /* init qsave stack */
3107   g_qsave_stack = NULL;
3108 
3109   /* init qsave_marking stack */
3110   g_qsave_marking_stack = NULL;
3111   g_buffer_pos   = 0;
3112   /* buffer contains empty string */
3113   g_buffer[0]    = '\0';
3114   /* try to chop entire stream if possible! Originally: FALSE; */
3115   /* turn on buffering only AFTER a save request */
3116   g_in_buffering_mode  = FALSE;
3117   /* try to chop entire stream if possible! Originally: FALSE; */
3118   /* turn on buffering only AFTER a save request */
3119   g_in_buffering_mode  = TRUE;
3120 
3121   /* bump page number */
3122   ++g_page_count;
3123   g_page_object_num  = PDFObject_New(/* in_fp */);
3124 }
3125 
3126 
3127 /*****************************************************************************/
3128 /*                                                                           */
3129 /*  void PDFPage_Cleanup(FILE* in_fp)                                        */
3130 /*                                                                           */
3131 /*  Cleans up the processing after a page's contents have been written out.  */
3132 /*                                                                           */
3133 /*****************************************************************************/
3134 
PDFPage_Cleanup(FILE * in_fp)3135 void PDFPage_Cleanup(FILE* in_fp)
3136 {
3137   BOOLEAN hasAnnot = FALSE;
3138 
3139   Assert(g_qsave_stack == NULL, no_fpos);
3140 
3141   /* if page has some content then close its stream object */
3142   if (g_page_contents_obj_num != 0)
3143   {
3144     PDF_FILE_OFFSET page_length = PDFPage_End(in_fp);
3145 
3146 #ifdef _CALC_LARGEST_PAGE_OBJECT_
3147     if (page_length > g_max_page_length)
3148       g_max_page_length = page_length;
3149 #endif
3150 
3151     /* write page's length object */
3152     if (g_PDF_debug)
3153       fprintf(in_fp, "%%\n%% length object for page %u:\n%%\n", g_page_count);
3154 
3155     PDFObject_WriteObj(in_fp, g_page_length_obj_num);
3156     fprintf(in_fp, "%u\nendobj\n", page_length);
3157 
3158     /* write out any used font resources */
3159     {
3160       t_font_list_entry_ptr entry = g_font_list;
3161       while (entry != NULL) {
3162 	PDFFont_WriteFontResource(in_fp, entry);
3163 	entry = entry->m_next_font_entry;
3164       }
3165     }
3166   }
3167 
3168   /* write out annotations */
3169   {
3170     t_source_annot_entry_ptr source = g_source_annot_list;
3171 
3172     while (source != NULL)
3173     {
3174       if (source->m_this_page_object_num == g_page_object_num)
3175       {
3176 
3177 	/* even if the annotation(s) cannot be written out now, flag the */
3178 	/* fact that this page has annotations                           */
3179 	hasAnnot = TRUE;
3180 
3181 	/* attempt to write out annotation */
3182 	PDFSourceAnnot_Write(in_fp, source);
3183       } /* if annot entry belongs to this page */
3184       source = source->m_next_entry;
3185     } /* while */
3186   }
3187 
3188   /* start writing page object ("/Type /Page"); remember its number */
3189   {
3190     unsigned int wanted_block_num = (g_page_count - 1) / kNumberOfPagesPerBlock;
3191     unsigned int block_pos = (g_page_count - 1) % kNumberOfPagesPerBlock;
3192     t_page_block_ptr the_block = g_cur_page_block;
3193 
3194     /* if first obj in a block then allocate the block */
3195     if (block_pos == 0)
3196     {
3197       the_block = (t_page_block_ptr) malloc(sizeof(t_page_block));
3198       if (the_block == NULL)
3199         Error(48, 38, "PDFPage_Cleanup: run out of memory", FATAL, no_fpos);
3200       if (wanted_block_num == 0)	/* if first block in file */
3201       {
3202 	Assert(g_page_block_list == NULL, no_fpos);
3203 	g_page_block_list = the_block;
3204       }
3205       else
3206       {
3207 	Assert(g_cur_page_block != NULL, no_fpos);
3208 	g_cur_page_block->m_next_block = the_block;
3209       }
3210       the_block->m_next_block = NULL;	/* don't forget to init this! */
3211       g_cur_page_block = the_block;
3212     }
3213     else
3214     {
3215       Assert(the_block != NULL, no_fpos);
3216     }
3217 
3218     /* save object number of this page for later use in the /Pages list */
3219     if (g_PDF_debug)
3220       fprintf(in_fp, "%%\n%% page number %u:\n%%\n", g_page_count);
3221     the_block->m_block[block_pos] = g_page_object_num;
3222     PDFObject_WriteObj(in_fp, g_page_object_num);
3223     /* PDFObject_WriteNewObj(in_fp); */
3224   }
3225 
3226   /* write out /Page ID */
3227   fputs("<<\n/Type /Page\n", in_fp);
3228 
3229   /* write out page size and orientation */
3230   fprintf(in_fp, "/CropBox [ 0 0 %u %u ]\n",g_doc_h_bound,g_doc_v_bound);
3231 
3232   /* write out parent object ref */
3233   fputs("/Parent ", in_fp);
3234   PDFObject_WriteRef(in_fp, g_pages_root);
3235   fputs("\n", in_fp);
3236 
3237   /* write out contents object ref (if it exists) */
3238   if (g_page_contents_obj_num != 0)
3239   {
3240     fputs("/Contents ", in_fp);
3241     PDFObject_WriteRef(in_fp, g_page_contents_obj_num);
3242     fputs("\n", in_fp);
3243   }
3244 
3245   /* open resources dictionary */
3246   if (g_page_uses_fonts || g_page_has_text || g_page_has_graphics)
3247     fputs("/Resources\n<<\n", in_fp);
3248 
3249   /* write out font resources used */
3250   if (g_page_uses_fonts)
3251   {
3252     t_font_list_entry_ptr entry = g_font_list;
3253     fputs("/Font <<", in_fp);
3254     while (entry != NULL) {
3255       if (entry->m_in_use) {
3256 	fprintf(in_fp, " %s ", entry->m_PDF_font_name);
3257 	PDFFont_WriteObjectRef(in_fp, entry);
3258       }
3259       entry = entry->m_next_font_entry;
3260     }
3261     fputs(" >>\n", in_fp);
3262   }
3263 
3264   /* write out any procsets used */
3265   if (g_page_has_text || g_page_has_graphics)
3266   {
3267     fputs("/ProcSet [ /PDF", in_fp);
3268     if (g_page_has_text)
3269       fputs(" /Text", in_fp);
3270     fputs(" ]\n", in_fp);
3271   }
3272 
3273   /* close resources dictionary */
3274   if (g_page_uses_fonts || g_page_has_text || g_page_has_graphics)
3275     fputs(">>\n", in_fp);
3276 
3277   /* write out annot array */
3278   if (hasAnnot)
3279   {
3280     t_source_annot_entry_ptr entry = g_source_annot_list;
3281     t_source_annot_entry_ptr previous_entry = NULL;
3282 
3283     /* write out annotations */
3284     fputs("/Annots [", in_fp);
3285     while (entry != NULL)
3286     {
3287       if (entry->m_this_page_object_num == g_page_object_num)
3288       {
3289 	fputs(" ", in_fp);
3290 	PDFObject_WriteRef(in_fp, entry->m_this_object_num);
3291 
3292 	/* if the annotation has just been written out above then delete it */
3293 	if (entry->m_written_to_PDF_file)
3294 	{
3295 	  t_source_annot_entry_ptr next_entry = entry->m_next_entry;
3296 	  if (g_source_annot_list == entry)
3297 		g_source_annot_list = next_entry;
3298 	  if (previous_entry != NULL)
3299 		previous_entry->m_next_entry = next_entry;
3300 	  PDFSourceAnnot_Dispose(entry);
3301 	  entry = next_entry;
3302 	}
3303 	else /* annot is a fwd referring one: defer deleting it */
3304 	{
3305 	  previous_entry = entry;
3306 	  entry = entry->m_next_entry;
3307 	}
3308       } /* if annot entry belongs to this page */
3309       else /* annot does not belong to this page; skip it */
3310       {
3311 	previous_entry = entry;
3312 	entry = entry->m_next_entry;
3313       }
3314     } /* while */
3315     fputs(" ]\n", in_fp);
3316   } /* if */
3317 
3318   /* close object */
3319   fputs(">>\nendobj\n", in_fp);
3320 }
3321 
3322 
3323 /*****************************************************************************/
3324 /*                                                                           */
3325 /*  void PDFFile_Init(FILE* in_fp, int in_h_bound, int in_v_bound)           */
3326 /*                                                                           */
3327 /*  Initialize this module.                                                  */
3328 /*                                                                           */
3329 /*****************************************************************************/
3330 
PDFFile_Init(FILE * in_fp,int in_h_bound,int in_v_bound,int in_IN,int in_CM,int in_PT,int in_EM)3331 void PDFFile_Init(FILE* in_fp, int in_h_bound, int in_v_bound,
3332   int in_IN, int in_CM, int in_PT, int in_EM)
3333 {
3334   /* write PDF header */
3335   fputs("%PDF-1.2\n", in_fp);			/* identifies this as PDF   */
3336   fputs("\045\342\343\317\323\n", in_fp);	/* 0x25 0xE2 0xE3 0xCF 0xD3 */
3337 
3338   /* set debugging status */
3339 #if DEBUG_ON
3340   g_PDF_debug = dbg[DPD].on[D] || dbg[DPD].on[DD] || dbg[DPD].on[DDD];
3341 #else
3342   g_PDF_debug = FALSE;
3343 #endif
3344 
3345 #if PDF_COMPRESSION
3346   g_apply_compression = !g_PDF_debug;
3347 #endif
3348 
3349   /* objects */
3350   g_next_objnum = 1; /* object numbers start at one */
3351   g_obj_offset_list = NULL;
3352   g_cur_obj_offset_block = NULL;
3353 
3354   /* fonts */
3355   g_font_list = NULL;
3356   g_font_encoding_list = NULL;
3357 
3358   /* pages */
3359   g_page_count = 0;
3360   g_page_block_list = NULL;
3361   g_cur_page_block = NULL;
3362   g_pages_root = PDFObject_New(/* in_fp */);
3363 
3364   /* doc */
3365   g_doc_h_bound = in_h_bound;
3366   g_doc_v_bound = in_v_bound;
3367   g_doc_author = NULL;
3368   g_doc_title = NULL;
3369   g_doc_subject = NULL;
3370   g_doc_keywords = NULL;
3371 
3372   /* link annotations */
3373   g_target_annot_list = NULL;
3374   g_has_exported_targets = FALSE;
3375   g_source_annot_list = NULL;
3376 
3377   /* units */
3378   g_units[k_in] = in_IN;
3379   g_units[k_cm] = in_CM;
3380   g_units[k_pt] = in_PT;
3381   g_units[k_em] = in_EM;
3382 
3383 }
3384 
3385 
3386 /*****************************************************************************/
3387 /*                                                                           */
3388 /*  void PDFFile_WritePagesObject(FILE* in_fp)                               */
3389 /*                                                                           */
3390 /*  Cleans up processing after all pages has been written out.               */
3391 /*                                                                           */
3392 /*****************************************************************************/
3393 
PDFFile_WritePagesObject(FILE * in_fp)3394 static void PDFFile_WritePagesObject(FILE* in_fp)
3395 {
3396   unsigned int  i;
3397   t_page_block_ptr the_block  = g_page_block_list;
3398 
3399   if (g_PDF_debug)
3400     fprintf(in_fp, "%%\n%% root of pages tree:\n%%\n");
3401 
3402   /* write out the root of the Pages tree */
3403   PDFObject_WriteObj(in_fp, g_pages_root);
3404   fputs("<<\n", in_fp);
3405   fputs("/Type /Pages\n", in_fp);
3406   fputs("/Kids [ ", in_fp);
3407   for (i = 0; i < g_page_count; i++)
3408   {
3409     int block_pos = i % kNumberOfPagesPerBlock;
3410     PDFObject_WriteRef(in_fp, the_block->m_block[block_pos]);
3411     if (block_pos == (kNumberOfPagesPerBlock - 1))
3412     {
3413       the_block = the_block->m_next_block;
3414       /* Assert(the_block != NULL, no_fpos);  not always true! */
3415     }
3416     fputs(" ", in_fp);
3417   }
3418   fprintf(in_fp, " ]\n/Count %u\n", g_page_count);
3419   /* ***
3420   fprintf(in_fp, "/MediaBox [ 0 0 612 792 ]\n");
3421   fprintf(in_fp, "/MediaBox [ 0 0 %u %u ]\n",g_doc_h_bound,g_doc_v_bound);
3422   *** */
3423   fprintf(in_fp, "/MediaBox [ 0 0 %u %u ]\n", g_doc_h_bound, g_doc_v_bound);
3424   fputs(">>\nendobj\n", in_fp);
3425 }
3426 
3427 
3428 /*****************************************************************************/
3429 /*                                                                           */
3430 /*  PDF_FILE_OFFSET PDFFile_WriteXREF(FILE* in_fp)                           */
3431 /*                                                                           */
3432 /*  Writes out the XREF table.                                               */
3433 /*                                                                           */
3434 /*****************************************************************************/
3435 
PDFFile_WriteXREF(FILE * in_fp)3436 static PDF_FILE_OFFSET PDFFile_WriteXREF(FILE* in_fp)
3437 {
3438   int i;
3439   PDF_FILE_OFFSET xref_start;
3440   t_offset_block_ptr the_block = g_obj_offset_list;
3441 
3442   if (g_PDF_debug)
3443     fprintf(in_fp, "%%\n%% xref table:\n%%\n");
3444 
3445   xref_start = ftell(in_fp);
3446   fputs("xref\n", in_fp);
3447   fprintf(in_fp, "0 %u\n", g_next_objnum);
3448   fputs("0000000000 65535 f \n", in_fp);	/* object 0 is a deleted obj */
3449   Assert( (g_next_objnum == 1) || (the_block != NULL), no_fpos);
3450   for (i = 1; i < g_next_objnum; i++)	/* write out list of object offsets */
3451   {
3452     int block_pos = (i - 1) % kNumberOfObjectsPerBlock;
3453 
3454     /* always write an entry (even if the object doesn't exist) */
3455     fprintf(in_fp, "%010u 00000 n \n", the_block->m_block[block_pos]);
3456 
3457     if (the_block->m_block[block_pos] == 0)
3458     {
3459       t_tempbuf str;
3460 
3461       strcpy(str, "PDFFile_WriteXREF: undefined object number: ");
3462       sprintf(str + strlen(str), "%u", i);
3463       Error(48, 39, "%s", WARN, no_fpos, str);
3464     }
3465 
3466     if (block_pos == (kNumberOfObjectsPerBlock - 1))
3467     {
3468       the_block = the_block->m_next_block;
3469       /* Assert(the_block != NULL, no_fpos);  not always true! */
3470     }
3471   }
3472   return xref_start;
3473 }
3474 
3475 /*****************************************************************************/
3476 /*                                                                           */
3477 /*  void PDFFile_Cleanup(FILE* in_fp)                                        */
3478 /*                                                                           */
3479 /*  Cleans up processing after all pages has been written out.               */
3480 /*                                                                           */
3481 /*****************************************************************************/
3482 
PDFFile_Cleanup(FILE * in_fp)3483 void PDFFile_Cleanup(FILE* in_fp)
3484 {
3485   PDF_FILE_OFFSET xref_start;	/* file offset of start of xref table */
3486   PDF_OBJECT_NUM catalog_obj_num;
3487   PDF_OBJECT_NUM info_obj_num;
3488   PDF_OBJECT_NUM dests_obj_num = 0;
3489 
3490   /* write out any unresolved link annotations.  This could be done earlier  */
3491   /* (in fact, it can be done as each new target is defined) but I've        */
3492   /* arbitrarily decided to do it here.                                      */
3493   {
3494     t_source_annot_entry_ptr source = g_source_annot_list;
3495 
3496     while (source != NULL)
3497     {
3498       t_target_annot_entry_ptr target;
3499 
3500       Assert(source->m_target == NULL, no_fpos);
3501       target = PDFTargetAnnot_Find(source->m_name);
3502       if (target != NULL)
3503       {
3504 	source->m_target = target;
3505 	PDFSourceAnnot_Write(in_fp, source);
3506       }
3507       source = source->m_next_entry;
3508     }
3509   }
3510 
3511   /* write out pages object */
3512   PDFFile_WritePagesObject(in_fp);
3513 
3514   /* if file has exported targets for links then write out /Dests dictionary */
3515   if (g_has_exported_targets)
3516   {
3517     t_target_annot_entry_ptr entry = g_target_annot_list;
3518 
3519     Assert(entry != NULL, no_fpos);	/* should be at least an entry! */
3520 
3521     /* write PDF 1.1 style /Dests dictionary */
3522     if (g_PDF_debug)
3523       fprintf(in_fp, "%%\n%% /Dests dictionary (exported links):\n%%\n");
3524 
3525     dests_obj_num = PDFObject_WriteNewObj(in_fp);
3526     fputs("<<\n", in_fp);
3527 
3528     while (entry != NULL)
3529     {
3530       if (entry->m_for_export)
3531       {
3532 	fprintf(in_fp, "/%s [ ", entry->m_name);
3533 	PDFObject_WriteRef(in_fp, entry->m_page_object_num);
3534 	fprintf(in_fp, " /XYZ null null null ]\n");
3535       }
3536       entry = entry->m_next_entry;
3537     }
3538     fputs(">>\nendobj\n", in_fp);
3539   }
3540 
3541   /* write out catalog object */
3542   if (g_PDF_debug)
3543     fprintf(in_fp, "%%\n%% catalog:\n%%\n");
3544 
3545   catalog_obj_num = PDFObject_WriteNewObj(in_fp);
3546   fputs("<<\n", in_fp);
3547   fputs("/Type /Catalog\n", in_fp);
3548   fputs("/Pages ", in_fp);
3549   PDFObject_WriteRef(in_fp, g_pages_root);
3550   fputs("\n", in_fp);
3551 
3552   /* if file has exported targets for links then write out a /Dest dictionary */
3553   if (g_has_exported_targets)
3554   {
3555     fputs("/Dests ", in_fp);
3556     PDFObject_WriteRef(in_fp, dests_obj_num);
3557     fputs("\n", in_fp);
3558   }
3559 
3560   /* ***
3561   fputs("/PageMode ", in_fp);
3562   switch ()
3563   {
3564   }
3565   fputs("\n", in_fp);
3566   *** */
3567 
3568   fputs(">>\nendobj\n", in_fp);
3569 
3570   /* write out info object */
3571   if (g_PDF_debug)
3572     fprintf(in_fp, "%%\n%% Info object:\n%%\n");
3573 
3574   /* ***
3575   Author string (Optional) The name of the person who created the document.
3576   CreationDate Date (Optional) The date the document was created.
3577   ModDate Date (Optional) The date the document was last modified.
3578   Creator string (Optional) If the document was converted into a PDF document from another
3579   form, this is the name of the application that created the original document.
3580   Producer string (Optional) The name of the application that converted the document from its native
3581   format to PDF.
3582   Title string (Optional) The document�s title.
3583   Subject string (Optional) The subject of the document.
3584   Keywords string (Optional) Keywords associated with the document.
3585 
3586   example:
3587 
3588   /Creator (Adobe Illustrator)
3589   /CreationDate (D:19930204080603-08'00')
3590   /Author (Werner Heisenberg)
3591   /Producer (Acrobat Network Distiller 1.0 for Macintosh)
3592   *** */
3593 
3594   info_obj_num = PDFObject_WriteNewObj(in_fp);
3595   fputs("<<\n", in_fp);
3596 
3597   fprintf(in_fp, "/Creator (%s)\n", LOUT_VERSION);
3598   fprintf(in_fp, "/Producer (%s)\n", LOUT_VERSION);
3599 
3600   {
3601     time_t now;
3602     struct tm *date;
3603 
3604     /* I will presume that localtime() is Y2K compliant.  If it isn't    */
3605     /* on your system, feel free to tweak this code. :-)                 */
3606 
3607     now = time( NULL );
3608     date = localtime( &now );
3609     fprintf(in_fp, "/CreationDate (D:%.4d%.2d%.2d%.2d%.2d%.2d)\n",
3610       date->tm_year + 1900, date->tm_mon + 1, date->tm_mday,
3611       date->tm_hour, date->tm_min, date->tm_sec);
3612   }
3613 
3614   if (g_doc_author != NULL)
3615     fprintf(in_fp, "/Author (%s)\n", g_doc_author);
3616 
3617   if (g_doc_title != NULL)
3618     fprintf(in_fp, "/Title (%s)\n", g_doc_title);
3619 
3620   if (g_doc_subject != NULL)
3621     fprintf(in_fp, "/Subject (%s)\n", g_doc_subject);
3622 
3623   if (g_doc_keywords != NULL)
3624     fprintf(in_fp, "/Keywords (%s)\n", g_doc_keywords);
3625 
3626   fputs(">>\nendobj\n", in_fp);
3627 
3628   /* write out xref table */
3629   xref_start = PDFFile_WriteXREF(in_fp);
3630 
3631   /* write out trailer */
3632   /* *** uwe: comments can appear in the body only.
3633   if (g_PDF_debug)
3634     fprintf(in_fp, "%%\n%% trailer:\n%%\n");
3635   *** */
3636 
3637   fputs("trailer\n<<\n", in_fp);
3638   fprintf(in_fp, "/Size %u\n", g_next_objnum);
3639   fputs("/Root ", in_fp);
3640   PDFObject_WriteRef(in_fp, catalog_obj_num);
3641   fputs("\n/Info ", in_fp);
3642   PDFObject_WriteRef(in_fp, info_obj_num);
3643 
3644   fprintf(in_fp, " >>\nstartxref\n%u\n", xref_start);
3645   fputs("%%EOF\n", in_fp);
3646 
3647   /* memory deallocation (no need to dispose of the qsave_marking_stack  */
3648   /* because it's always empty after a page has been processed)          */
3649 
3650   while (g_obj_offset_list != NULL)
3651   {
3652     t_offset_block_ptr the_block = g_obj_offset_list;
3653     g_obj_offset_list = the_block->m_next_block;
3654     free(the_block);
3655   }
3656 
3657   while (g_font_encoding_list != NULL)
3658   {
3659     t_font_encoding_entry_ptr the_block = g_font_encoding_list;
3660     g_font_encoding_list = the_block->m_next_entry;
3661     free(the_block->m_font_encoding);
3662     free(the_block);
3663   }
3664 
3665   while (g_font_list != NULL)
3666   {
3667     t_font_list_entry_ptr the_block = g_font_list;
3668     g_font_list = the_block->m_next_font_entry;
3669     free(the_block->m_PDF_font_name);
3670     free(the_block->m_short_font_name);
3671     free(the_block->m_actual_font_name);
3672     free(the_block);
3673   }
3674 
3675   while (g_page_block_list != NULL)
3676   {
3677     t_page_block_ptr the_block = g_page_block_list;
3678     g_page_block_list = the_block->m_next_block;
3679     free(the_block);
3680   }
3681 
3682   while (g_source_annot_list != NULL)
3683   {
3684     t_source_annot_entry_ptr entry = g_source_annot_list;
3685 
3686     if (entry->m_target == NULL)
3687     {
3688       t_tempbuf str;
3689       strcpy(str, "PDFFile_Cleanup: unresolved link annotation named ");
3690       strcat(str, (char*) entry->m_name);
3691       Error(48, 40, "%s", WARN, no_fpos, str);
3692     }
3693 
3694     g_source_annot_list = PDFSourceAnnot_Dispose(entry);
3695   }
3696 
3697   while (g_target_annot_list != NULL)
3698   {
3699     t_target_annot_entry_ptr entry = g_target_annot_list;
3700     g_target_annot_list = entry->m_next_entry;
3701     free(entry->m_name);
3702     free(entry);
3703   }
3704 
3705 #ifdef _CALC_LARGEST_PAGE_OBJECT_
3706   /* display largest page object */
3707   {
3708     t_tempbuf str;
3709     /* JK sprintf(str, "The largest page object is %u bytes long.", g_max_page_length); */
3710     Error(48, 41, "The largest page object is %u bytes long.", WARN, no_fpos, g_max_page_length);
3711   }
3712 #endif
3713 }
3714