OSDN Git Service

update.
[putex/putex.git] / src / dvipdfmx-pu / src / dvipdfmx.c
1 /*  
2     
3     This is DVIPDFMx, an eXtended version of DVIPDFM by Mark A. Wicks.
4
5     Copyright (C) 2009-2013 by Jin-Hwan Cho, Matthias Franz, and Shunsaku Hirata,
6     the dvipdfmx project team.
7     
8     Copyright (C) 1998, 1999 by Mark A. Wicks <mwicks@kettering.edu>
9
10     This program is free software; you can redistribute it and/or modify
11     it under the terms of the GNU General Public License as published by
12     the Free Software Foundation; either version 2 of the License, or
13     (at your option) any later version.
14     
15     This program is distributed in the hope that it will be useful,
16     but WITHOUT ANY WARRANTY; without even the implied warranty of
17     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18     GNU General Public License for more details.
19     
20     You should have received a copy of the GNU General Public License
21     along with this program; if not, write to the Free Software
22     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
23 */
24
25 #if HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <stdio.h>
30 #include <string.h>
31 #include <limits.h>
32 #include <ctype.h>
33
34 #include "system.h"
35 #include "mem.h"
36
37 #include "dpxconf.h"
38 #include "dpxfile.h"
39 #include "dpxutil.h"
40
41 #include "dvi.h"
42
43 #include "pdflimits.h"
44 #include "pdfdoc.h"
45 #include "pdfdev.h"
46 #include "pdfparse.h"
47 #include "pdfencrypt.h"
48
49 #include "spc_tpic.h"
50 #include "specials.h"
51
52 #include "mpost.h"
53
54 #include "fontmap.h"
55 #include "pdffont.h"
56 #include "pdfximage.h"
57 #include "cid.h"
58
59 #include "dvipdfmx.h"
60 #include "xbb.h"
61
62 #include "error.h"
63
64 int compat_mode = 0;     /* 0 = dvipdfmx, 1 = dvipdfm */
65
66 static int verbose = 0;
67
68 static int mp_mode = 0;
69
70 static long opt_flags = 0;
71
72 #define OPT_TPIC_TRANSPARENT_FILL (1 << 1)
73 #define OPT_CIDFONT_FIXEDPITCH    (1 << 2)
74 #define OPT_FONTMAP_FIRST_MATCH   (1 << 3)
75 #define OPT_PDFDOC_NO_DEST_REMOVE (1 << 4)
76
77 static char   ignore_colors = 0;
78 static double annot_grow    = 0.0;
79 static int    bookmark_open = 0;
80 static double mag           = 1.0;
81 static int    font_dpi      = 600;
82 static int    really_quiet  = 0;
83 /*
84  * Precision is essentially limited to 0.01pt.
85  * See, dev_set_string() in pdfdev.c.
86  */
87 static int pdfdecimaldigits = 2;
88
89 /* Image cache life in hours */
90 /*  0 means erase all old images and leave new images */
91 /* -1 means erase all old images and also erase new images */
92 /* -2 means ignore image cache (default) */
93 static int image_cache_life = -2;
94
95 /* Encryption */
96 static int do_encryption    = 0;
97 static unsigned key_bits    = 40;
98 static unsigned permission  = 0x003C;
99
100 /* Page device */
101 static double paper_width  = 595.0;
102 static double paper_height = 842.0;
103 static double x_offset = 72.0;
104 static double y_offset = 72.0;
105 static char   landscape_mode    = 0;
106
107
108 char *dvi_filename = NULL, *pdf_filename = NULL;
109
110 static void
111 read_config_file (const char *config);
112
113 #ifdef WIN32
114 #define STRN_CMP strncasecmp
115 #else
116 #define STRN_CMP strncmp
117 #endif
118
119 static void
120 set_default_pdf_filename(void)
121 {
122   const char *dvi_base;
123
124   dvi_base = xbasename(dvi_filename);
125   if (mp_mode &&
126       strlen(dvi_base) > 4 &&
127       !STRN_CMP(".mps", dvi_base + strlen(dvi_base) - 4, 4)) {
128     pdf_filename = NEW(strlen(dvi_base)+1, char);
129     strncpy(pdf_filename, dvi_base, strlen(dvi_base) - 4);
130     pdf_filename[strlen(dvi_base)-4] = '\0';
131   } else if (strlen(dvi_base) > 4 &&
132              !STRN_CMP(".dvi", dvi_base+strlen(dvi_base)-4, 4)) {
133     pdf_filename = NEW(strlen(dvi_base)+1, char);
134     strncpy(pdf_filename, dvi_base, strlen(dvi_base)-4);
135     pdf_filename[strlen(dvi_base)-4] = '\0';
136   } else {
137     pdf_filename = NEW(strlen(dvi_base)+5, char);
138     strcpy(pdf_filename, dvi_base);
139   }
140
141   strcat (pdf_filename, ".pdf");
142 }
143
144 static void
145 show_version (void)
146 {
147   fprintf(stdout, "\nThis is %s-%s by the DVIPDFMx project team,\n", PACKAGE, VERSION);
148   fprintf(stdout, "modified for TeX Live,\n");
149   fprintf(stdout, "an extended version of dvipdfm-0.13.2c developed by Mark A. Wicks.\n");
150   fprintf(stdout, "\nCopyright (C) 2002-2013 by the DVIPDFMx project team\n");
151   fprintf(stdout, "\nThis is free software; you can redistribute it and/or modify\n");
152   fprintf(stdout, "it under the terms of the GNU General Public License as published by\n");
153   fprintf(stdout, "the Free Software Foundation; either version 2 of the License, or\n");
154   fprintf(stdout, "(at your option) any later version.\n");
155 }
156
157 static void
158 show_usage (void)
159 {
160   fprintf(stdout, "\nUsage: dvipdfmx [options] dvifile\n");
161   fprintf(stdout, "-c \t\tIgnore color specials (for B&W printing)\n");
162   fprintf(stdout, "-d number\tSet PDF decimal digits (0-5) [2]\n");
163   fprintf(stdout, "-f filename\tSet font map file name [cid-x.map]\n");
164   fprintf(stdout, "-g dimension\tAnnotation \"grow\" amount [0.0in]\n");
165   fprintf(stdout, "-l \t\tLandscape mode\n");
166   fprintf(stdout, "-m number\tSet additional magnification\n");
167   fprintf(stdout, "-o filename\tSet output file name [dvifile.pdf]\n");
168   fprintf(stdout, "-p papersize\tSet papersize [a4]\n");
169   fprintf(stdout, "-q \t\tBe quiet\n");
170   fprintf(stdout, "-r resolution\tSet resolution (in DPI) for raster fonts [600]\n");
171   fprintf(stdout, "-s pages\tSelect page ranges (-)\n");
172   fprintf(stdout, "-t \t\tEmbed thumbnail images of PNG format [dvifile.1] \n");
173   fprintf(stdout, "-x dimension\tSet horizontal offset [1.0in]\n");
174   fprintf(stdout, "-y dimension\tSet vertical offset [1.0in]\n");
175   fprintf(stdout, "-z number  \tSet zlib compression level (0-9) [9]\n");
176
177   fprintf(stdout, "-v \t\tBe verbose\n");
178   fprintf(stdout, "-vv\t\tBe more verbose\n");
179   fprintf(stdout, "-C number\tSpecify miscellaneous option flags [0]:\n");
180   fprintf(stdout, "\t\t  0x0001 reserved\n");
181   fprintf(stdout, "\t\t  0x0002 Use semi-transparent filling for tpic shading command,\n");
182   fprintf(stdout, "\t\t\t instead of opaque gray color. (requires PDF 1.4)\n");
183   fprintf(stdout, "\t\t  0x0004 Treat all CIDFont as fixed-pitch font.\n");
184   fprintf(stdout, "\t\t  0x0008 Do not replace duplicate fontmap entries.\n");
185   fprintf(stdout, "\t\t  0x0010 Do not optimize PDF destinations.\n");
186   fprintf(stdout, "\t\tPositive values are always ORed with previously given flags.\n");
187   fprintf(stdout, "\t\tAnd negative values replace old values.\n");
188   fprintf(stdout, "-D template\tPS->PDF conversion command line template [none]\n");
189   fprintf(stdout, "-E \t\tEnable DVIPDFM emulation mode\n");
190   fprintf(stdout, "-I number\tImage cache life in hours [-2]\n");
191   fprintf(stdout, "         \t 0: erase all old images and leave new images\n");
192   fprintf(stdout, "         \t-1: erase all old images and also erase new images\n");
193   fprintf(stdout, "         \t-2: ignore image cache\n");
194   fprintf(stdout, "-K number\tEncryption key length [40]\n");
195   fprintf(stdout, "-O number\tSet maximum depth of open bookmark items [0]\n");
196   fprintf(stdout, "-P number\tSet permission flags for PDF encryption [0x003C]\n");
197   fprintf(stdout, "-S \t\tEnable PDF encryption\n");
198   fprintf(stdout, "-V number\tSet PDF minor version [4]\n");
199   fprintf(stdout, "\nAll dimensions entered on the command line are \"true\" TeX dimensions.\n");
200   fprintf(stdout, "Argument of \"-s\" lists physical page ranges separated by commas, e.g., \"-s 1-3,5-6\"\n");
201   fprintf(stdout, "Papersize is specified by paper format (e.g., \"a4\") or by w<unit>,h<unit> (e.g., \"20cm,30cm\").\n");
202 }
203
204 static void
205 usage (void)
206 {
207   if (really_quiet)
208     return;
209   fprintf(stdout, "\nTry \"dvipdfmx --help\" for more information.\n");
210   exit(1);
211 }
212
213
214 static int
215 read_length (double *vp, const char **pp, const char *endptr)
216 {
217   char   *q;
218   const char *p = *pp;
219   double  v, u = 1.0;
220   const char *_ukeys[] = {
221 #define K_UNIT__PT  0
222 #define K_UNIT__IN  1
223 #define K_UNIT__CM  2
224 #define K_UNIT__MM  3
225 #define K_UNIT__BP  4
226     "pt", "in", "cm", "mm", "bp",
227      NULL
228   };
229   int     k, error = 0;
230
231   q = parse_float_decimal(&p, endptr);
232   if (!q) {
233     *vp = 0.0; *pp = p;
234     return  -1;
235   }
236
237   v = atof(q);
238   RELEASE(q);
239
240   q = parse_c_ident(&p, endptr);
241   if (q) {
242     if (strlen(q) > strlen("true") &&
243         !memcmp(q, "true", strlen("true"))) {
244       q += strlen("true"); /* just skip "true" */
245     }
246     for (k = 0; _ukeys[k] && strcmp(_ukeys[k], q); k++);
247     switch (k) {
248     case K_UNIT__PT: u *= 72.0 / 72.27; break;
249     case K_UNIT__IN: u *= 72.0; break;
250     case K_UNIT__CM: u *= 72.0 / 2.54 ; break;
251     case K_UNIT__MM: u *= 72.0 / 25.4 ; break;
252     case K_UNIT__BP: u *= 1.0 ; break;
253     default:
254       WARN("Unknown unit of measure: %s", q);
255       error = -1;
256       break;
257     }
258     RELEASE(q);
259   }
260
261   *vp = v * u; *pp = p;
262   return  error;
263 }
264
265 static void
266 select_paper (const char *paperspec)
267 {
268   const struct paper *pi;
269   int   error = 0;
270
271   pi = paperinfo(paperspec);
272   if (pi && papername(pi)) {
273     paper_width  = paperpswidth (pi);
274     paper_height = paperpsheight(pi);
275   } else {
276     const char  *p = paperspec, *endptr, *comma;
277     comma  = strchr(p, ',');
278     endptr = p + strlen(p);
279     if (!comma)
280       ERROR("Unrecognized paper format: %s", paperspec);
281     error = read_length(&paper_width,  &p, comma);
282     p = comma + 1;
283     error = read_length(&paper_height, &p, endptr);
284   }
285   if (error || paper_width <= 0.0 || paper_height <= 0.0)
286     ERROR("Invalid paper size: %s (%.2fx%.2f)", paperspec, paper_width, paper_height);
287 }
288
289 struct page_range 
290 {
291   long first, last;
292 } *page_ranges = NULL;
293
294 int num_page_ranges = 0;
295 int max_page_ranges = 0;
296
297 static void
298 select_pages (const char *pagespec)
299 {
300   char  *q;
301   const char *p = pagespec;
302
303   while (*p != '\0') {
304     /* Enlarge page range table if necessary */
305     if (num_page_ranges >= max_page_ranges) {
306       max_page_ranges += 4;
307       page_ranges = RENEW(page_ranges, max_page_ranges, struct page_range);
308     }
309
310     page_ranges[num_page_ranges].first = 0;
311     page_ranges[num_page_ranges].last  = 0;
312
313     for ( ; *p && isspace(*p); p++);
314     q = parse_unsigned(&p, p + strlen(p)); /* Can't be signed. */
315     if (q) { /* '-' is allowed here */
316       page_ranges[num_page_ranges].first = atoi(q) - 1;
317       page_ranges[num_page_ranges].last  = page_ranges[num_page_ranges].first;
318       RELEASE(q);
319     }
320     for ( ; *p && isspace(*p); p++);
321
322     if (*p == '-') {
323       for (++p; *p && isspace(*p); p++);
324       page_ranges[num_page_ranges].last = -1;
325       if (*p) {
326         q = parse_unsigned(&p, p + strlen(p));
327         if (q) {
328           page_ranges[num_page_ranges].last = atoi(q) - 1;
329           RELEASE(q);
330         }
331         for ( ; *p && isspace(*p); p++);
332       }
333     } else {
334       page_ranges[num_page_ranges].last = page_ranges[num_page_ranges].first;
335     }
336
337     num_page_ranges++;
338
339     if (*p == ',')
340       p++;
341     else  {
342       for ( ; *p && isspace(*p); p++);
343       if (*p)
344         ERROR("Bad page range specification: %s", p);
345     }
346   }
347   return;
348 }
349
350 #define POP_ARG() {argv += 1; argc -= 1;}
351 /* It doesn't work as expected (due to dvi filename). */
352 #define CHECK_ARG(n,m) if (argc < (n) + 1) {\
353   if (!really_quiet)\
354     fprintf(stderr, "\nMissing %s after \"-%c\".\n", (m), *flag);\
355   usage();\
356 }
357
358 static void
359 set_verbose (int argc, char *argv[])
360 {
361   while (argc > 0) {
362     if(*argv[0] == '-') {
363       char *flag;
364
365       for (flag = argv[0] + 1; *flag != 0; flag++) {
366         if (*flag == '-')
367           break;
368         if (*flag == 'q')
369           really_quiet = 1;
370         if (*flag == 'v')
371           verbose++;
372       }
373     }
374     POP_ARG();
375   }
376
377   if (!really_quiet) {
378     int i;
379
380     for (i = 0; i < verbose; i++) {
381       dvi_set_verbose();
382       pdf_dev_set_verbose();
383       pdf_doc_set_verbose();
384       pdf_enc_set_verbose();
385       pdf_obj_set_verbose();
386       pdf_fontmap_set_verbose();
387       dpx_file_set_verbose();
388     }
389   }
390 }
391
392
393 static void
394 do_args (int argc, char *argv[])
395 {
396   while (argc > 0 && *argv[0] == '-') {
397     char *flag, *nextptr;
398     const char *nnextptr;
399
400     for (flag = argv[0] + 1; *flag != 0; flag++) {
401       switch (*flag) {
402       case '-':
403         if (++flag) {
404           if (!strcmp(flag, "help")) {
405             show_version();
406             show_usage();
407             exit(0);
408           } else if (!strcmp(flag, "version")) {
409             show_version();
410             exit(0);
411           }
412         }
413         if (!really_quiet)
414           fprintf(stderr, "Unknown option in \"--%s\"", flag);
415         usage();
416         break;
417       case 'D':
418         CHECK_ARG(1, "PS->PDF conversion command line template");
419         set_distiller_template(argv[1]);
420         POP_ARG();
421         break;
422       case 'r':
423         CHECK_ARG(1, "bitmap font dpi");
424         font_dpi = atoi(argv[1]);
425         if (font_dpi <= 0)
426           ERROR("Invalid bitmap font dpi specified: %s", argv[1]);
427         POP_ARG();
428         break;
429       case 'm':
430         CHECK_ARG(1, "magnification value");
431         mag = strtod(argv[1], &nextptr);
432         if (mag < 0.0 || nextptr == argv[1])
433           ERROR("Invalid magnification specifiied: %s", argv[1]);
434         POP_ARG();
435         break;
436       case 'g':
437         CHECK_ARG(1, "annotation \"grow\" amount");
438         nnextptr = nextptr = argv[1];
439         read_length(&annot_grow, &nnextptr, nextptr + strlen(nextptr));
440         POP_ARG();
441         break;
442       case 'x':
443         CHECK_ARG(1, "horizontal offset value");
444         nnextptr = nextptr = argv[1];
445         read_length(&x_offset, &nnextptr, nextptr + strlen(nextptr));
446         POP_ARG();
447         break;
448       case 'y':
449         CHECK_ARG(1, "vertical offset value");
450         nnextptr = nextptr = argv[1];
451         read_length(&y_offset, &nnextptr, nextptr + strlen(nextptr));
452         POP_ARG();
453         break;
454       case 'o':
455         CHECK_ARG(1, "output file name");
456         pdf_filename = NEW (strlen(argv[1])+1,char);
457         strcpy(pdf_filename, argv[1]);
458         POP_ARG();
459         break;
460       case 's':
461         CHECK_ARG(1, "page selection specification");
462         select_pages(argv[1]);
463         POP_ARG();
464         break;
465       case 't':
466         pdf_doc_enable_manual_thumbnails();
467         break;
468       case 'p':
469         CHECK_ARG(1, "paper format/size");
470         select_paper(argv[1]);
471         POP_ARG();
472         break;
473       case 'c':
474         ignore_colors = 1;
475         break;
476       case 'l':
477         landscape_mode = 1;
478         break;
479       case 'f':
480         CHECK_ARG(1, "fontmap file name");
481         if (opt_flags & OPT_FONTMAP_FIRST_MATCH)
482           pdf_load_fontmap_file(argv[1], FONTMAP_RMODE_APPEND);
483         else
484           pdf_load_fontmap_file(argv[1], FONTMAP_RMODE_REPLACE);
485         POP_ARG();
486         break;
487       case 'q': case 'v':
488         break;
489       case 'V':
490       {
491         int ver_minor;
492
493         if (isdigit(*(flag+1))) {
494           flag++;
495           ver_minor = atoi(flag);
496         } else {
497           CHECK_ARG(1, "PDF minor version number");
498           ver_minor = atoi(argv[1]);
499           POP_ARG();
500         }
501         if (ver_minor < PDF_VERSION_MIN) {
502           WARN("PDF version 1.%d not supported. Using PDF 1.%d instead.",
503                ver_minor, PDF_VERSION_MIN);
504           ver_minor = PDF_VERSION_MIN;
505         } else if (ver_minor > PDF_VERSION_MAX) {
506           WARN("PDF version 1.%d not supported. Using PDF 1.%d instead.",
507                ver_minor, PDF_VERSION_MAX);
508           ver_minor = PDF_VERSION_MAX;
509         }
510         pdf_set_version((unsigned) ver_minor);
511       }
512       break;
513       case 'z':
514       {
515         int level;
516
517         if (isdigit(*(flag+1))) {
518           flag++;
519           level = atoi(flag);
520         } else {
521           CHECK_ARG(1, "compression level");
522           level = atoi(argv[1]);
523           POP_ARG();
524         }
525         pdf_set_compression(level);
526       }
527       break;
528       case 'd':
529         if (compat_mode) {
530           WARN("dvipdfm \"-d\" option not supported.");
531           break;
532         }
533         if (isdigit(*(flag+1))) {
534           flag++;
535           pdfdecimaldigits = atoi(flag);
536         } else {
537           CHECK_ARG(1, "number of fractional digits");
538           pdfdecimaldigits = atoi(argv[1]);
539           POP_ARG();
540         }
541         break;
542       case 'I':
543         CHECK_ARG(1, "image cache life in hours");
544         image_cache_life = atoi(argv[1]);
545         POP_ARG();
546         break;
547       case 'S':
548         do_encryption = 1;
549         break;
550       case 'K': 
551         CHECK_ARG(1, "encryption key length");
552         key_bits = (unsigned) atoi(argv[1]);
553         if (key_bits < 40 || key_bits > 128 || (key_bits & 0x7))
554           ERROR("Invalid encryption key length specified: %s", argv[1]);
555         POP_ARG();
556         break;
557       case 'P': 
558         CHECK_ARG(1, "encryption permission flag");
559         permission = (unsigned) strtoul(argv[1], &nextptr, 0);
560         if (nextptr == argv[1])
561           ERROR("Invalid encryption permission flag: %s", argv[1]);
562         POP_ARG();
563         break;
564       case 'O':
565         /* Bookmark open level */
566         CHECK_ARG(1, "bookmark open level");
567         bookmark_open = atoi(argv[1]);
568         POP_ARG();
569         break;
570       case 'M':
571         mp_mode = 1;
572         break;
573       case 'C':
574         CHECK_ARG(1, "a number");
575         {
576           long flags;
577
578           flags = (unsigned) strtol(argv[1], &nextptr, 0);
579           if (nextptr == argv[1])
580             ERROR("Invalid flag: %s", argv[1]);
581           if (flags < 0)
582             opt_flags  = -flags;
583           else
584             opt_flags |=  flags;
585         }
586         POP_ARG();
587         break;
588       case 'E':
589         compat_mode = 1;
590         break;
591       case 'i':
592         CHECK_ARG(1, "subsidiary config file");
593         read_config_file(argv[1]);
594         POP_ARG();
595         break;
596       case 'e':
597         if (compat_mode) {
598           WARN("dvipdfm \"-e\" option not supported.");
599           break;
600         } /* else fall through */
601       default:
602         if (!really_quiet)
603           fprintf(stderr, "Unknown option in \"-%s\"", flag);
604         usage();
605         break;
606       }
607     }
608     POP_ARG();
609   }
610
611   if (argc > 1) {
612     if (!really_quiet)
613       fprintf(stderr, "Multiple dvi filenames?");
614     usage();
615   } else if (argc > 0) {
616     /*
617      * The only legitimate way to have argc == 0 here is
618      * do_args was called from config file.  In that case, there is
619      * no dvi file name.  Check for that case .
620      */
621     if (!mp_mode && STRN_CMP(".dvi", argv[0] + strlen(argv[0]) - 4, 4)) {
622       dvi_filename = NEW(strlen(argv[0]) + 5, char);
623       strcpy(dvi_filename, argv[0]);
624       strcat(dvi_filename, ".dvi");
625     } else {
626       dvi_filename = NEW(strlen(argv[0]) + 1, char);
627       strcpy(dvi_filename, argv[0]);
628     }
629   }
630 }
631
632 static void
633 cleanup (void)
634 {
635   if (dvi_filename)
636     RELEASE(dvi_filename);
637   if (pdf_filename)
638     RELEASE(pdf_filename);
639   if (page_ranges)
640     RELEASE(page_ranges);
641 }
642
643 static void
644 read_config_file (const char *config)
645 {
646   const char *start, *end;
647   char *option;
648   FILE *fp;
649
650   fp = DPXFOPEN(config, DPX_RES_TYPE_TEXT);
651   if (!fp) {
652     WARN("Could not open config file \"%s\".", config);
653     return;
654   }
655   while ((start = mfgets (work_buffer, WORK_BUFFER_SIZE, fp)) != NULL) {
656     char *argv[2];
657     int   argc;
658
659     argc = 0;
660     end = work_buffer + strlen(work_buffer);
661     skip_white (&start, end);
662     if (start >= end)
663       continue;
664     /* Build up an argument list as if it were passed on the command
665        line */
666     if ((option = parse_ident (&start, end))) {
667       argc = 1;
668       argv[0] = NEW (strlen(option)+2, char);
669       strcpy (argv[0]+1, option);
670       RELEASE (option);
671       *argv[0] = '-';
672       skip_white (&start, end);
673       if (start < end) {
674         argc += 1;
675         if (*start == '"') {
676           argv[1] = parse_c_string (&start, end);
677         }
678         else
679           argv[1] = parse_ident (&start, end);
680       }
681     }
682     do_args (argc, argv);
683     while (argc > 0) {
684       RELEASE (argv[--argc]);
685     }
686   }
687   if (fp)
688     MFCLOSE(fp);
689 }
690
691 static void
692 system_default (void)
693 {
694   if (systempapername() != NULL) {
695     select_paper(systempapername());
696   } else if (defaultpapername() != NULL) {
697     select_paper(defaultpapername());
698   }
699 }
700
701 void
702 error_cleanup (void)
703 {
704   pdf_close_images();  /* delete temporary files */
705   pdf_error_cleanup();
706   if (pdf_filename) {
707     remove(pdf_filename);
708     if (!really_quiet)
709       fprintf(stderr, "\nOutput file removed.\n");
710   }
711 }
712
713 #define SWAP(v1,v2) do {\
714    double _tmp = (v1);\
715    (v1) = (v2);\
716    (v2) = _tmp;\
717  } while (0)
718
719 static void
720 do_dvi_pages (void)
721 {
722   long     page_no, page_count, i, step;
723   double   page_width, page_height;
724   pdf_rect mediabox;
725
726   spc_exec_at_begin_document();
727
728   if (num_page_ranges == 0) {
729     if (!page_ranges) {
730       page_ranges = NEW(1, struct page_range);
731       max_page_ranges = 1;
732     }
733     page_ranges[0].first = 0;
734     page_ranges[0].last  = -1; /* last page */
735     num_page_ranges = 1;
736   }
737
738   page_width  = paper_width;
739   page_height = paper_height;
740   page_count  = 0;
741
742   mediabox.llx = 0.0;
743   mediabox.lly = 0.0;
744   mediabox.urx = paper_width;
745   mediabox.ury = paper_height;
746
747   pdf_doc_set_mediabox(0, &mediabox); /* Root node */
748
749   for (i = 0; i < num_page_ranges; i++) {
750     if (page_ranges[i].last < 0)
751       page_ranges[i].last += dvi_npages();
752
753     step    = (page_ranges[i].first <= page_ranges[i].last) ? 1 : -1;
754     page_no = page_ranges[i].first;
755     for (;;) {
756       if (page_no < dvi_npages()) {
757         double w, h, xo, yo;
758         char   lm;
759
760         MESG("[%d", page_no+1);
761         /* Users want to change page size even after page is started! */
762         w = page_width; h = page_height; lm = landscape_mode;
763         xo = x_offset; yo = y_offset;
764         dvi_scan_specials(page_no, &w, &h, &xo, &yo, &lm, NULL, NULL, NULL, NULL, NULL, NULL);
765         if (lm != landscape_mode) {
766           SWAP(w, h);
767           landscape_mode = lm;
768         }
769         if (page_width  != w || page_height != h) {
770           page_width  = w;
771           page_height = h;
772         }
773         if (x_offset != xo || y_offset != yo) {
774           x_offset = xo;
775           y_offset = yo;
776         }
777         if (page_width  != paper_width ||
778             page_height != paper_height) {
779           mediabox.llx = 0.0;
780           mediabox.lly = 0.0;
781           mediabox.urx = page_width;
782           mediabox.ury = page_height;
783           pdf_doc_set_mediabox(page_count+1, &mediabox);
784         }
785         dvi_do_page(page_no,
786                     page_width, page_height, x_offset, y_offset);
787         page_count++;
788         MESG("]");
789       }
790
791       if (step > 0 &&
792           page_no >= page_ranges[i].last)
793         break;
794       else if (step < 0 &&
795                page_no <= page_ranges[i].last)
796         break;
797       else {
798         page_no += step;
799       }
800     }
801   }
802
803   if (page_count < 1) {
804     ERROR("No pages fall in range!");
805   }
806
807   spc_exec_at_end_document();
808 }
809
810 static void
811 do_mps_pages (void)
812 {
813   FILE  *fp;
814
815   /* _FIXME_ */
816   fp = MFOPEN(dvi_filename, FOPEN_RBIN_MODE);
817   if (fp) {
818     mps_do_page(fp);
819     MFCLOSE(fp);
820   } else {
821     int   i, page_no, step, page_count = 0;
822     char *filename;
823     /* Process filename.1, filename.2,... */
824     filename = NEW(strlen(dvi_filename) + 16 + 1, char);
825     for (i = 0; i < num_page_ranges; i++) {
826       if (page_ranges[i].last < 0)
827         ERROR("Invalid page number for MPS input: -1");
828
829       step    = (page_ranges[i].first <= page_ranges[i].last) ? 1 : -1;
830       page_no = page_ranges[i].first;
831       for (;;) {
832         sprintf(filename, "%s.%d", dvi_filename, page_no + 1);
833         fp = MFOPEN(filename, FOPEN_RBIN_MODE);
834         if (fp) {
835           MESG("[%d<%s>", page_no + 1, filename);
836           mps_do_page(fp);
837           page_count++;
838           MESG("]");
839           MFCLOSE(fp);
840         }
841         if (step > 0 &&
842             page_no >= page_ranges[i].last)
843           break;
844         else if (step < 0 &&
845                  page_no <= page_ranges[i].last)
846           break;
847         else {
848           page_no += step;
849         }
850       }
851     }
852     RELEASE(filename);
853     if (page_count == 0)
854       ERROR("No page output for \"%s\".", dvi_filename);
855   }
856 }
857
858
859 /* TODO: MetaPost mode */
860 #if defined(MIKTEX)
861 #  define main Main
862 #endif
863 int CDECL
864 main (int argc, char *argv[]) 
865 {
866   double dvi2pts;
867
868   {
869     const char *base = xbasename(argv[0]);
870
871     if (STRN_CMP(base, "dvipdfmx", 8) != 0 &&
872         (STRN_CMP(base, "dvipdfm",7) == 0 || STRN_CMP(base, "ebb", 3) == 0))
873       compat_mode = 1;
874
875     if (STRN_CMP(base, "extractbb", 9) == 0 ||
876         STRN_CMP(base, "xbb", 3) == 0 ||
877         STRN_CMP(base, "ebb", 3) == 0)
878       return extractbb(argc, argv);
879   }
880
881   if (argc < 2) {
882     if (!really_quiet)
883       fprintf(stderr, "No dvi filename specified.");
884     usage();
885     return 1;
886   }
887
888 #ifdef MIKTEX
889   miktex_initialize();
890 #else
891   kpse_set_program_name(argv[0], PACKAGE);
892 #endif
893
894   paperinit();
895   system_default();
896
897   argv+=1;
898   argc-=1;
899
900   set_verbose(argc, argv);
901   /* quiet mode cannot be set in config file */
902   if (really_quiet)
903     shut_up();
904
905   pdf_init_fontmaps(); /* This must come before parsing options... */
906
907   read_config_file(DPX_CONFIG_FILE);
908
909   do_args (argc, argv);
910
911 #ifndef MIKTEX
912   kpse_init_prog("", font_dpi, NULL, NULL);
913   kpse_set_program_enabled(kpse_pk_format, true, kpse_src_texmf_cnf);
914 #endif
915   pdf_font_set_dpi(font_dpi);
916   dpx_delete_old_cache(image_cache_life);
917
918   if (!dvi_filename) {
919     WARN("No dvi filename specified.");
920     usage();
921     return 1;
922   }
923
924   /* Check for ".dvi" at end of argument name */
925   if (pdf_filename == NULL)
926     set_default_pdf_filename();
927
928   MESG("%s -> %s\n", dvi_filename, pdf_filename);
929
930   pdf_enc_compute_id_string(dvi_filename, pdf_filename);
931   if (do_encryption) {
932     if (key_bits > 40 && pdf_get_version() < 4)
933       ERROR("Chosen key length requires at least PDF 1.4. "
934             "Use \"-V 4\" to change.");
935     pdf_enc_set_passwd(key_bits, permission, NULL, NULL);
936   }
937
938   if (mp_mode) {
939     x_offset = 0.0;
940     y_offset = 0.0;
941     dvi2pts  = 0.01; /* dvi2pts controls accuracy. */
942   } else {
943     unsigned ver_minor = 0;
944     char owner_pw[MAX_PWD_LEN], user_pw[MAX_PWD_LEN];
945     /* Dependency between DVI and PDF side is rather complicated... */
946     dvi2pts = dvi_init(dvi_filename, mag);
947     if (dvi2pts == 0.0)
948       ERROR("dvi_init() failed!");
949
950     pdf_doc_set_creator(dvi_comment());
951
952     if (do_encryption)
953       /* command line takes precedence */
954       dvi_scan_specials(0, &paper_width, &paper_height, &x_offset, &y_offset, &landscape_mode,
955                         &ver_minor, NULL, NULL, NULL, NULL, NULL);
956     else {
957       dvi_scan_specials(0, &paper_width, &paper_height, &x_offset, &y_offset, &landscape_mode,
958                         &ver_minor, &do_encryption, &key_bits, &permission, owner_pw, user_pw);
959       if (do_encryption) {
960         if (key_bits < 40 || key_bits > 128 || (key_bits & 0x7))
961           ERROR("Invalid encryption key length specified: %u", key_bits);
962         else if (key_bits > 40 && pdf_get_version() < 4)
963           ERROR("Chosen key length requires at least PDF 1.4. "
964                 "Use \"-V 4\" to change.");
965         do_encryption = 1;
966         pdf_enc_set_passwd(key_bits, permission, owner_pw, user_pw);
967       }
968     }
969     if (ver_minor >= PDF_VERSION_MIN && ver_minor <= PDF_VERSION_MAX) {
970       pdf_set_version(ver_minor);
971     }
972     if (landscape_mode) {
973       SWAP(paper_width, paper_height);
974     }
975   }
976
977   pdf_files_init();
978
979   /* Set default paper size here so that all page's can inherite it.
980    * annot_grow:    Margin of annotation.
981    * bookmark_open: Miximal depth of open bookmarks.
982    */
983   pdf_open_document(pdf_filename, do_encryption,
984                     paper_width, paper_height, annot_grow, bookmark_open,
985                     !(opt_flags & OPT_PDFDOC_NO_DEST_REMOVE));
986
987   /* Ignore_colors placed here since
988    * they are considered as device's capacity.
989    */
990   pdf_init_device(dvi2pts, pdfdecimaldigits, ignore_colors);
991
992   if (opt_flags & OPT_CIDFONT_FIXEDPITCH)
993     CIDFont_set_flags(CIDFONT_FORCE_FIXEDPITCH);
994
995   /* Please move this to spc_init_specials(). */
996   if (opt_flags & OPT_TPIC_TRANSPARENT_FILL)
997     tpic_set_fill_mode(1);
998
999   if (mp_mode) {
1000     do_mps_pages();
1001   } else {
1002     do_dvi_pages();
1003   }
1004
1005   pdf_files_close();
1006
1007   /* Order of close... */
1008   pdf_close_device  ();
1009   /* pdf_close_document flushes XObject (image) and other resources. */
1010   pdf_close_document();
1011
1012   pdf_close_fontmaps(); /* pdf_font may depend on fontmap. */
1013
1014   if (!mp_mode)
1015     dvi_close();
1016
1017   MESG("\n");
1018   cleanup();
1019
1020   paperdone();
1021 #ifdef MIKTEX
1022   miktex_uninitialize ();
1023 #endif
1024
1025   return 0;
1026 }